Add full avalon support (pass regression)

This commit is contained in:
Charles Papon 2017-07-21 17:40:45 +02:00
parent 52f5020e64
commit 54f785b1a3
6 changed files with 193 additions and 1 deletions

View File

@ -20,6 +20,7 @@ This repository host an RISC-V implementation written in SpinalHDL. There is som
- Pipelined on 5 stages (Fetch, Decode, Execute, Memory, WriteBack)
- 1.16 DMIPS/Mhz when all features are enabled
- Optimized for FPGA
- AXI4 and Avalon ready
- Optional MUL/DIV extension
- Optional instruction and data caches
- Optional MMU

View File

@ -4,6 +4,7 @@ import VexRiscv._
import spinal.core._
import spinal.lib._
import spinal.lib.bus.amba4.axi._
import spinal.lib.bus.avalon.{AvalonMMConfig, AvalonMM}
case class DBusSimpleCmd() extends Bundle{
@ -36,6 +37,13 @@ object DBusSimpleBus{
useLen = false,
useResp = true
)
def getAvalonConfig() = AvalonMMConfig.pipelined(
addressWidth = 32,
dataWidth = 32).copy(
useByteEnable = true,
maximumPendingReadTransactions = 1
)
}
case class DBusSimpleBus() extends Bundle with IMasterSlave{
val cmd = Stream(DBusSimpleCmd())
@ -92,6 +100,35 @@ case class DBusSimpleBus() extends Bundle with IMasterSlave{
// axi2 << axi
axi2
}
def toAvalon(stageCmd : Boolean = true): AvalonMM = {
val avalonConfig = DBusSimpleBus.getAvalonConfig()
val mm = AvalonMM(avalonConfig)
val cmdStage = if(stageCmd) cmd.stage else cmd
mm.read := cmdStage.valid && !cmdStage.wr
mm.write := cmdStage.valid && cmdStage.wr
mm.address := (cmdStage.address >> 2) @@ U"00"
mm.writeData := cmdStage.size.mux (
U(0) -> cmdStage.data(7 downto 0) ## cmdStage.data(7 downto 0) ## cmdStage.data(7 downto 0) ## cmdStage.data(7 downto 0),
U(1) -> cmdStage.data(15 downto 0) ## cmdStage.data(15 downto 0),
default -> 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
cmdStage.ready := mm.waitRequestn
rsp.ready :=mm.readDataValid
rsp.error := False //TODO
rsp.data := mm.readData
mm
}
}

View File

@ -4,6 +4,7 @@ import VexRiscv.{Stageable, ExceptionService, ExceptionCause, VexRiscv}
import spinal.core._
import spinal.lib._
import spinal.lib.bus.amba4.axi._
import spinal.lib.bus.avalon.{AvalonMMConfig, AvalonMM}
case class IBusSimpleCmd() extends Bundle{
@ -33,6 +34,13 @@ object IBusSimpleBus{
useResp = true,
useSize = false
)
def getAvalonConfig() = AvalonMMConfig.pipelined(
addressWidth = 32,
dataWidth = 32
).getReadOnlyConfig.copy(
maximumPendingReadTransactions = 1
)
}
case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMasterSlave{
var cmd = Stream(IBusSimpleCmd())
@ -68,6 +76,22 @@ case class IBusSimpleBus(interfaceKeepData : Boolean) extends Bundle with IMaste
// axi2 << axi
axi2
}
def toAvalon(): AvalonMM = {
assert(!interfaceKeepData)
val avalonConfig = IBusSimpleBus.getAvalonConfig()
val mm = AvalonMM(avalonConfig)
mm.read := cmd.valid
mm.address := (cmd.pc >> 2) @@ U"00"
cmd.ready := mm.waitRequestn
rsp.ready := mm.readDataValid
rsp.inst := mm.readData
rsp.error := False //TODO
mm
}
}
class IBusSimplePlugin(interfaceKeepData : Boolean, catchAccessFault : Boolean) extends Plugin[VexRiscv]{

View File

@ -33,7 +33,7 @@ object TestsWorkspace {
plugins = List(
new PcManagerSimplePlugin(0x00000000l, false),
// new IBusSimplePlugin(
// interfaceKeepData = true,
// interfaceKeepData = false,
// catchAccessFault = true
// ),
new IBusCachedPlugin(
@ -229,12 +229,24 @@ object TestsWorkspace {
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())

View File

@ -131,12 +131,24 @@ object VexRiscvAvalon{
cpu.rework {
var iBus : AvalonMM = null
for (plugin <- cpuConfig.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())

View File

@ -491,6 +491,53 @@ public:
};
#endif
#ifdef IBUS_SIMPLE_AVALON
#include <queue>
struct IBusSimpleAvalonRsp{
uint32_t data;
bool error;
};
class IBusSimpleAvalon : public SimElement{
public:
queue<IBusSimpleAvalonRsp> rsps;
Workspace *ws;
VVexRiscv* top;
IBusSimpleAvalon(Workspace* ws){
this->ws = ws;
this->top = ws->top;
}
virtual void onReset(){
top->iBusAvalon_waitRequestn = 1;
top->iBusAvalon_readDataValid = 0;
}
virtual void preCycle(){
if (top->iBusAvalon_read && top->iBusAvalon_waitRequestn) {
IBusSimpleAvalonRsp rsp;
ws->iBusAccess(top->iBusAvalon_address,&rsp.data,&rsp.error);
rsps.push(rsp);
}
}
//TODO doesn't catch when instruction removed ?
virtual void postCycle(){
if(!rsps.empty() && (!ws->iStall || VL_RANDOM_I(7) < 100)){
IBusSimpleAvalonRsp rsp = rsps.front(); rsps.pop();
top->iBusAvalon_readDataValid = 1;
top->iBusAvalon_readData = rsp.data;
} else {
top->iBusAvalon_readDataValid = 0;
top->iBusAvalon_readData = VL_RANDOM_I(32);
}
if(ws->iStall)
top->iBusAvalon_waitRequestn = VL_RANDOM_I(7) < 100;
}
};
#endif
#ifdef IBUS_CACHED
class IBusCached : public SimElement{
@ -635,6 +682,59 @@ public:
};
#endif
#ifdef DBUS_SIMPLE_AVALON
#include <queue>
struct DBusSimpleAvalonRsp{
uint32_t data;
bool error;
};
class DBusSimpleAvalon : public SimElement{
public:
queue<DBusSimpleAvalonRsp> rsps;
Workspace *ws;
VVexRiscv* top;
DBusSimpleAvalon(Workspace* ws){
this->ws = ws;
this->top = ws->top;
}
virtual void onReset(){
top->dBusAvalon_waitRequestn = 1;
top->dBusAvalon_readDataValid = 0;
}
virtual void preCycle(){
if (top->dBusAvalon_write && top->dBusAvalon_waitRequestn) {
bool dummy;
ws->dBusAccess(top->dBusAvalon_address,1,2,top->dBusAvalon_byteEnable,&top->dBusAvalon_writeData,&dummy);
}
if (top->dBusAvalon_read && top->dBusAvalon_waitRequestn) {
DBusSimpleAvalonRsp rsp;
ws->dBusAccess(top->dBusAvalon_address,0,2,0xF,&rsp.data,&rsp.error);
rsps.push(rsp);
}
}
//TODO doesn't catch when instruction removed ?
virtual void postCycle(){
if(!rsps.empty() && (!ws->iStall || VL_RANDOM_I(7) < 100)){
DBusSimpleAvalonRsp rsp = rsps.front(); rsps.pop();
top->dBusAvalon_readDataValid = 1;
top->dBusAvalon_readData = rsp.data;
} else {
top->dBusAvalon_readDataValid = 0;
top->dBusAvalon_readData = VL_RANDOM_I(32);
}
if(ws->iStall)
top->dBusAvalon_waitRequestn = VL_RANDOM_I(7) < 100;
}
};
#endif
#ifdef DBUS_CACHED
class DBusCached : public SimElement{
public:
@ -1039,6 +1139,9 @@ void Workspace::fillSimELements(){
#ifdef IBUS_SIMPLE
simElements.push_back(new IBusSimple(this));
#endif
#ifdef IBUS_SIMPLE_AVALON
simElements.push_back(new IBusSimpleAvalon(this));
#endif
#ifdef IBUS_CACHED
simElements.push_back(new IBusCached(this));
#endif
@ -1048,6 +1151,9 @@ void Workspace::fillSimELements(){
#ifdef DBUS_SIMPLE
simElements.push_back(new DBusSimple(this));
#endif
#ifdef DBUS_SIMPLE_AVALON
simElements.push_back(new DBusSimpleAvalon(this));
#endif
#ifdef DBUS_CACHED
simElements.push_back(new DBusCached(this));
#endif