Merge remote-tracking branch 'origin/cfu' into dev
This commit is contained in:
commit
51d22d4a8c
|
@ -4,7 +4,7 @@ ENTRY( _start )
|
||||||
|
|
||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
ram : ORIGIN = 0x80000000, LENGTH = 64k
|
ram : ORIGIN = DEFINED(__ram_origin) ? __ram_origin : 0x80000000, LENGTH = 64k
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,17 @@ SRCS = $(wildcard src/*.c) \
|
||||||
|
|
||||||
LDSCRIPT = ${STANDALONE}/common/ram.ld
|
LDSCRIPT = ${STANDALONE}/common/ram.ld
|
||||||
|
|
||||||
|
sim: CFLAGS += -DSIM
|
||||||
|
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/riscv64-unknown-elf.mk
|
||||||
include ${STANDALONE}/common/standalone.mk
|
include ${STANDALONE}/common/standalone.mk
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
#ifndef CONFIG_H
|
#ifndef CONFIG_H
|
||||||
#define CONFIG_H
|
#define CONFIG_H
|
||||||
|
|
||||||
//#define QEMU
|
#ifndef OS_CALL
|
||||||
#define SIM
|
|
||||||
#define OS_CALL 0xC0000000
|
#define OS_CALL 0xC0000000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DTB
|
||||||
#define DTB 0xC3000000
|
#define DTB 0xC3000000
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -144,5 +144,92 @@ void halInit(){
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef LITEX
|
||||||
|
|
||||||
|
// this is copied from LiteX <hw/common.h>
|
||||||
|
#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 <generated/csr.h>
|
||||||
|
|
||||||
|
#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){
|
||||||
|
// protect against writing to a full tx fifo
|
||||||
|
while(uart_txfull_read());
|
||||||
|
uart_rxtx_write(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t getC(){
|
||||||
|
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(){
|
||||||
|
cpu_timer_latch_write(0);
|
||||||
|
uint32_t result = (uint32_t)cpu_timer_time_read();
|
||||||
|
cpu_timer_latch_write(1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rdtimeh(){
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,7 @@ void trap(){
|
||||||
#ifdef SIM
|
#ifdef SIM
|
||||||
uint32_t instruction = csr_read(mbadaddr);
|
uint32_t instruction = csr_read(mbadaddr);
|
||||||
#endif
|
#endif
|
||||||
#ifdef QEMU
|
#if defined(QEMU) || defined(LITEX)
|
||||||
uint32_t instruction = 0;
|
uint32_t instruction = 0;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
if (mepc & 2) {
|
if (mepc & 2) {
|
||||||
|
|
|
@ -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())
|
||||||
|
}
|
|
@ -0,0 +1,144 @@
|
||||||
|
package vexriscv.plugin
|
||||||
|
|
||||||
|
import vexriscv.{DecoderService, ExceptionCause, ExceptionService, Stage, Stageable, VexRiscv}
|
||||||
|
import spinal.core._
|
||||||
|
import spinal.lib._
|
||||||
|
|
||||||
|
case class CfuParameter(stageCount : Int,
|
||||||
|
allowZeroLatency : Boolean,
|
||||||
|
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 : 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 cmd = Stream(CfuCmd(p))
|
||||||
|
val rsp = Stream(CfuRsp(p))
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
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 = master(CfuBus(p))
|
||||||
|
joinException = pipeline.service(classOf[ExceptionService]).newExceptionPort(joinStage)
|
||||||
|
|
||||||
|
val decoderService = pipeline.service(classOf[DecoderService])
|
||||||
|
|
||||||
|
//custom-0
|
||||||
|
decoderService.add(List(
|
||||||
|
M"000000-----------000-----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),
|
||||||
|
RS1_USE -> True,
|
||||||
|
RS2_USE -> True
|
||||||
|
)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
override def build(pipeline: VexRiscv): Unit = {
|
||||||
|
import pipeline._
|
||||||
|
import pipeline.config._
|
||||||
|
|
||||||
|
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._
|
||||||
|
|
||||||
|
//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(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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue