From c8280a9a88498473cfd0f18fb5e674d494245894 Mon Sep 17 00:00:00 2001 From: Mateusz Holenko Date: Wed, 10 Jul 2019 10:38:38 +0200 Subject: [PATCH 1/8] 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 19dc3d9..2ebf858 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 2/8] 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 191ae9f..6e251ad 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 3/8] 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 e861785..d9d9098 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 6e251ad..afce2d5 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 4/8] 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 d9d9098..7534d08 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 52bb0e4..a9189f2 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 2102818..dc12fb8 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 5/8] 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 a9189f2..5a151bb 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 6/8] 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 0000000..968580d --- /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 7/8] 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 968580d..e34b2e7 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 8/8] 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 0000000..9983814 --- /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 e34b2e7..334fc25 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 + } } } }