From 94f19032f09e6a548c0298a3a19b2dec92f563f1 Mon Sep 17 00:00:00 2001 From: Charles Papon Date: Fri, 10 Mar 2023 14:44:14 +0800 Subject: [PATCH] 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 ed7e37e..44f41d9 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 ca72a91..7c2174b 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 3366e72..8a1c668 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 db3868f..cf0653f 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{