Add ICache and DCache axi bridges functions

Add StaticMemoryTranslationPlugin
This commit is contained in:
Charles Papon 2017-06-01 17:54:56 +02:00
parent ac16558b6b
commit 1e18daecc0
10 changed files with 277 additions and 95 deletions

View File

@ -8,7 +8,7 @@ import spinal.lib._
class DBusCachedPlugin(config : DataCacheConfig, askMemoryTranslation : Boolean = false, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv]{
class DBusCachedPlugin(config : DataCacheConfig, memoryTranslatorPortConfig : Any = null) extends Plugin[VexRiscv]{
import config._
var dBus : DataCacheMemBus = null
var mmuBus : MemoryTranslatorBus = null
@ -55,8 +55,7 @@ class DBusCachedPlugin(config : DataCacheConfig, askMemoryTranslation : Boolean
REG2_USE -> True
))
if(askMemoryTranslation)
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(pipeline.memory,memoryTranslatorPortConfig)
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(pipeline.memory,memoryTranslatorPortConfig)
if(catchSomething)
exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(pipeline.writeBack)
@ -104,15 +103,9 @@ class DBusCachedPlugin(config : DataCacheConfig, askMemoryTranslation : Boolean
cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE)
cache.io.cpu.memory.isStuck := arbitration.isStuck
cache.io.cpu.memory.isRemoved := arbitration.removeIt
if(mmuBus != null){
cache.io.cpu.memory.mmuBus <> mmuBus
} else {
cache.io.cpu.memory.mmuBus.rsp.physicalAddress := cache.io.cpu.memory.mmuBus.cmd.virtualAddress
cache.io.cpu.memory.mmuBus.rsp.allowExecute := True
cache.io.cpu.memory.mmuBus.rsp.allowRead := True
cache.io.cpu.memory.mmuBus.rsp.allowWrite := True
cache.io.cpu.memory.mmuBus.rsp.allowUser := True
}
arbitration.haltIt setWhen(cache.io.cpu.memory.haltIt)
cache.io.cpu.memory.mmuBus <> mmuBus
}
writeBack plug new Area{

View File

@ -74,6 +74,9 @@ class IBusCachedPlugin(config : InstructionCacheConfig, askMemoryTranslation : B
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.miss := False
}
}

View File

@ -0,0 +1,40 @@
package SpinalRiscv.Plugin
import SpinalRiscv.{VexRiscv, _}
import spinal.core._
import spinal.lib._
import scala.collection.mutable.ArrayBuffer
case class StaticMemoryTranslatorPort(bus : MemoryTranslatorBus, stage : Stage)
class StaticMemoryTranslatorPlugin(ioRange : UInt => Bool) extends Plugin[VexRiscv] with MemoryTranslator {
val portsInfo = ArrayBuffer[StaticMemoryTranslatorPort]()
override def newTranslationPort(stage : Stage,args : Any): MemoryTranslatorBus = {
// val exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(stage)
val port = StaticMemoryTranslatorPort(MemoryTranslatorBus(),stage)
portsInfo += port
port.bus
}
override def setup(pipeline: VexRiscv): Unit = {
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
import Riscv._
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.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.miss := False
}
}
}
}

View File

@ -105,52 +105,55 @@ object TopLevel {
val configFull = VexRiscvConfig(
plugins = List(
new PcManagerSimplePlugin(0x00000000l, false),
new IBusSimplePlugin(
interfaceKeepData = true,
catchAccessFault = true
),
// new IBusCachedPlugin(
// config = InstructionCacheConfig(
// cacheSize = 4096,
// bytePerLine =32,
// wayCount = 1,
// wrappedMemAccess = true,
// addressWidth = 32,
// cpuDataWidth = 32,
// memDataWidth = 32,
// catchIllegalAccess = true,
// catchAccessFault = true,
// catchMemoryTranslationMiss = true,
// asyncTagMemory = false,
// twoStageLogic = true
// ),
// new IBusSimplePlugin(
// interfaceKeepData = true,
// catchAccessFault = true
// ),
new IBusCachedPlugin(
config = InstructionCacheConfig(
cacheSize = 4096,
bytePerLine =32,
wayCount = 1,
wrappedMemAccess = true,
addressWidth = 32,
cpuDataWidth = 32,
memDataWidth = 32,
catchIllegalAccess = true,
catchAccessFault = true,
catchMemoryTranslationMiss = true,
asyncTagMemory = false,
twoStageLogic = 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,
// catchMemoryTranslationMiss = true
// ),
// askMemoryTranslation = true,
// 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,
catchMemoryTranslationMiss = true
),
memoryTranslatorPortConfig = null
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
// portTlbSize = 6
// )
// ),
),
new StaticMemoryTranslatorPlugin(
ioRange = _(31 downto 28) === 0xF
),
// new MemoryTranslatorPlugin(
// tlbSize = 32,
// virtualRange = _(31 downto 28) === 0xC,

View File

@ -3,6 +3,7 @@ package SpinalRiscv.demo
import SpinalRiscv.Plugin._
import SpinalRiscv._
import SpinalRiscv.ip.{DataCacheConfig, InstructionCacheConfig}
import spinal.core._
import spinal.lib._
import spinal.lib.bus.amba3.apb._
@ -124,14 +125,55 @@ class Briey(config: BrieyConfig) extends Component{
val configLight = VexRiscvConfig(
plugins = List(
new PcManagerSimplePlugin(0x00000000l, false),
new IBusSimplePlugin(
interfaceKeepData = false,
catchAccessFault = false
// new IBusSimplePlugin(
// interfaceKeepData = false,
// catchAccessFault = false
// ),
new IBusCachedPlugin(
config = InstructionCacheConfig(
cacheSize = 4096,
bytePerLine =32,
wayCount = 1,
wrappedMemAccess = true,
addressWidth = 32,
cpuDataWidth = 32,
memDataWidth = 32,
catchIllegalAccess = false,
catchAccessFault = false,
catchMemoryTranslationMiss = false,
asyncTagMemory = false,
twoStageLogic = true
)
// askMemoryTranslation = true,
// memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
// portTlbSize = 4
// )
),
new DBusSimplePlugin(
catchAddressMisaligned = false,
catchAccessFault = false
),
// new DBusCachedPlugin(
// config = new DataCacheConfig(
// cacheSize = 4096,
// bytePerLine = 32,
// wayCount = 1,
// addressWidth = 32,
// cpuDataWidth = 32,
// memDataWidth = 32,
// catchAccessError = false,
// catchIllegal = false,
// catchUnaligned = false,
// catchMemoryTranslationMiss = false
// ),
// memoryTranslatorPortConfig = null
// // memoryTranslatorPortConfig = MemoryTranslatorPortConfig(
// // portTlbSize = 6
// // )
// ),
// new StaticMemoryTranslatorPlugin(
// ioRange = _(31 downto 28) === 0xF
// ),
new DecoderSimplePlugin(
catchIllegalInstruction = false
),
@ -168,7 +210,9 @@ class Briey(config: BrieyConfig) extends Component{
var debugBus : Apb3 = null
for(plugin <- configLight.plugins) plugin match{
case plugin : IBusSimplePlugin => iBus = plugin.iBus.toAxi4ReadOnly()
case plugin : IBusCachedPlugin => iBus = plugin.iBus.toAxi4ReadOnly()
case plugin : DBusSimplePlugin => dBus = plugin.dBus.toAxi4Shared()
case plugin : DBusCachedPlugin => dBus = plugin.dBus.toAxi4Shared()
case plugin : DebugPlugin => {
resetCtrl.coreResetUnbuffered setWhen(plugin.io.resetOut)
debugBus = plugin.io.bus.toApb3()

View File

@ -3,6 +3,7 @@ package SpinalRiscv.ip
import SpinalRiscv._
import spinal.core._
import spinal.lib._
import spinal.lib.bus.amba4.axi.{Axi4Shared, Axi4Config}
case class DataCacheConfig( cacheSize : Int,
@ -17,9 +18,19 @@ case class DataCacheConfig( cacheSize : Int,
catchMemoryTranslationMiss : Boolean,
clearTagsAfterReset : Boolean = true,
tagSizeShift : Int = 0){ //Used to force infering ram
def burstSize = bytePerLine*8/memDataWidth
def burstSize = bytePerLine*8/memDataWidth
val burstLength = bytePerLine/(memDataWidth/8)
def catchSomething = catchUnaligned || catchMemoryTranslationMiss || catchIllegal || catchAccessError
def getAxi4SharedConfig() = Axi4Config(
addressWidth = addressWidth,
dataWidth = memDataWidth,
useId = false,
useRegion = false,
useBurst = false,
useLock = false,
useQos = false
)
}
@ -130,10 +141,12 @@ case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSl
val isValid = Bool
val isStuck = Bool
val isRemoved = Bool
val haltIt = Bool
val mmuBus = MemoryTranslatorBus()
override def asMaster(): Unit = {
out(isValid, isStuck, isRemoved)
in(haltIt)
slave(mmuBus)
}
}
@ -173,7 +186,7 @@ case class DataCacheMemCmd(p : DataCacheConfig) extends Bundle{
val address = UInt(p.addressWidth bit)
val data = Bits(p.memDataWidth bits)
val mask = Bits(p.memDataWidth/8 bits)
val length = UInt(log2Up(p.burstLength+1) bit)
val length = UInt(log2Up(p.burstLength) bits)
}
case class DataCacheMemRsp(p : DataCacheConfig) extends Bundle{
val data = Bits(p.memDataWidth bit)
@ -188,6 +201,50 @@ case class DataCacheMemBus(p : DataCacheConfig) extends Bundle with IMasterSlave
master(cmd)
slave(rsp)
}
def toAxi4Shared(stageCmd : Boolean = false): Axi4Shared = {
val axi = Axi4Shared(p.getAxi4SharedConfig())
val pendingWritesMax = 7
val pendingWrites = CounterUpDown(
stateCount = pendingWritesMax + 1,
incWhen = axi.sharedCmd.fire && axi.sharedCmd.write,
decWhen = axi.writeRsp.fire
)
val cmdPreFork = if (stageCmd) cmd.stage.stage().s2mPipe() else cmd
val (cmdFork, dataFork) = StreamFork2(cmdPreFork.haltWhen((pendingWrites =/= 0 && !cmdPreFork.wr) || pendingWrites === pendingWritesMax))
axi.sharedCmd.arbitrationFrom(cmdFork)
axi.sharedCmd.write := cmdFork.wr
axi.sharedCmd.prot := "010"
axi.sharedCmd.cache := "1111"
axi.sharedCmd.size := log2Up(p.memDataWidth/8)
axi.sharedCmd.addr := cmdFork.address
axi.sharedCmd.len := cmdFork.length.resized
val dataStage = dataFork.throwWhen(!dataFork.wr)
axi.writeData.arbitrationFrom(dataStage)
axi.writeData.last := True
axi.writeData.data := dataStage.data
axi.writeData.strb := dataStage.mask
rsp.valid := axi.r.valid
rsp.error := !axi.r.isOKAY()
rsp.data := axi.r.data
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
}
}
@ -349,10 +406,8 @@ class DataCache(p : DataCacheConfig) extends Component{
when(!dataReadRestored) {
dataReadCmd.valid := True
dataReadCmd.payload := way.dataReadRspOneAddress //Restore stage one readed value
assert(io.cpu.memory.isStuck,"Should not issue instructions when a victim line is not entirly in the victim cache",FAILURE)
}
dataReadRestored := True
}
}
@ -383,7 +438,7 @@ class DataCache(p : DataCacheConfig) extends Component{
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
io.mem.cmd.length := p.burstLength-1
io.mem.cmd.data := bufferReaded.payload
io.mem.cmd.mask := (1<<(wordWidth/8))-1
@ -412,6 +467,8 @@ class DataCache(p : DataCacheConfig) extends Component{
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.haltIt := io.cpu.memory.isValid && request.kind === MEMORY && !request.wr && victim.request.valid && !victim.dataReadRestored
}
val stageB = new Area {
@ -498,7 +555,7 @@ class DataCache(p : DataCacheConfig) extends Component{
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 := 1
io.mem.cmd.length := 0
when(!memCmdSent) {
io.mem.cmd.valid := True
@ -548,7 +605,7 @@ class DataCache(p : DataCacheConfig) extends Component{
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
io.mem.cmd.length := p.burstLength-1
}
when(valid && io.mem.cmd.ready){

View File

@ -3,6 +3,7 @@ package SpinalRiscv.ip
import SpinalRiscv._
import spinal.core._
import spinal.lib._
import spinal.lib.bus.amba4.axi.{Axi4ReadOnly, Axi4Config}
case class InstructionCacheConfig( cacheSize : Int,
@ -20,6 +21,15 @@ case class InstructionCacheConfig( cacheSize : Int,
def burstSize = bytePerLine*8/memDataWidth
def catchSomething = catchAccessFault || catchMemoryTranslationMiss || catchIllegalAccess
def getAxi4Config() = Axi4Config(
addressWidth = addressWidth,
dataWidth = memDataWidth,
useId = false,
useRegion = false,
useLock = false,
useQos = false,
useSize = false
)
}
@ -89,6 +99,7 @@ case class InstructionCacheCpuBus(p : InstructionCacheConfig) extends Bundle wit
case class InstructionCacheMemCmd(p : InstructionCacheConfig) extends Bundle{
val address = UInt(p.addressWidth bit)
}
case class InstructionCacheMemRsp(p : InstructionCacheConfig) extends Bundle{
val data = Bits(32 bit)
val error = Bool
@ -102,8 +113,30 @@ case class InstructionCacheMemBus(p : InstructionCacheConfig) extends Bundle wit
master(cmd)
slave(rsp)
}
def toAxi4ReadOnly(): Axi4ReadOnly = {
val axiConfig = p.getAxi4Config()
val mm = Axi4ReadOnly(axiConfig)
mm.readCmd.valid := cmd.valid
mm.readCmd.len := p.burstSize-1
mm.readCmd.addr := cmd.address
mm.readCmd.prot := "110"
mm.readCmd.cache := "1111"
if(p.wrappedMemAccess)
mm.readCmd.setBurstWRAP()
else
mm.readCmd.setBurstINCR()
cmd.ready := mm.readCmd.ready
rsp.valid := mm.readRsp.valid
rsp.data := mm.readRsp.data
rsp.error := !mm.readRsp.isOKAY()
mm.readRsp.ready := True
mm
}
}
case class InstructionCacheFlushBus() extends Bundle with IMasterSlave{
val cmd = Event
val rsp = Bool

View File

@ -1,47 +1,56 @@
[*]
[*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI
[*] Sun May 28 13:48:58 2017
[*] Wed May 31 17:28:39 2017
[*]
[dumpfile] "/home/spinalvm/Spinal/VexRiscv/src/test/cpp/regression/debugPluginExternal.vcd"
[dumpfile_mtime] "Sun May 28 12:59:45 2017"
[dumpfile_size] 905973760
[dumpfile_mtime] "Wed May 31 17:28:23 2017"
[dumpfile_size] 285487729
[savefile] "/home/spinalvm/Spinal/VexRiscv/src/test/cpp/regression/fail.gtkw"
[timestart] 1181704
[timestart] 1754228
[size] 1776 953
[pos] -1 -353
*-6.000000 1181914 -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] -775 -353
*-5.000000 1754292 -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.
[sst_width] 201
[signals_width] 392
[treeopen] TOP.VexRiscv.
[sst_width] 264
[signals_width] 416
[sst_expanded] 1
[sst_vpaned_height] 279
@22
TOP.VexRiscv.DebugPlugin_busReadDataReg[31:0]
@28
TOP.VexRiscv.DebugPlugin_firstCycle
TOP.VexRiscv.DebugPlugin_haltIt
TOP.VexRiscv.DebugPlugin_haltedByBreak
TOP.VexRiscv.DebugPlugin_insertDecodeInstruction
TOP.VexRiscv.DebugPlugin_isPipActive
TOP.VexRiscv.DebugPlugin_isPipBusy
TOP.VexRiscv.DebugPlugin_resetIt
TOP.VexRiscv.DebugPlugin_stepIt
TOP.VexRiscv.debugReset
@22
TOP.VexRiscv.debug_bus_cmd_payload_address[7:0]
TOP.VexRiscv.debug_bus_cmd_payload_data[31:0]
@28
TOP.VexRiscv.debug_bus_cmd_payload_wr
@29
TOP.VexRiscv.debug_bus_cmd_ready
@28
TOP.VexRiscv.debug_bus_cmd_valid
@22
TOP.VexRiscv.debug_bus_rsp_data[31:0]
@28
TOP.VexRiscv.debug_resetOut
TOP.VexRiscv.decode_LEGAL_INSTRUCTION
TOP.VexRiscv.CsrPlugin_exception
TOP.VexRiscv.clk
@22
TOP.VexRiscv.dataCache_1.io_cpu_execute_args_address[31:0]
@28
TOP.VexRiscv.dataCache_1.io_cpu_execute_args_clean
@22
TOP.VexRiscv.dataCache_1.io_cpu_execute_args_data[31:0]
@28
TOP.VexRiscv.dataCache_1.io_cpu_execute_args_forceUncachedAccess
@29
TOP.VexRiscv.dataCache_1.io_cpu_execute_args_invalidate
@28
TOP.VexRiscv.dataCache_1.io_cpu_execute_args_kind[0]
TOP.VexRiscv.dataCache_1.io_cpu_execute_args_size[1:0]
TOP.VexRiscv.dataCache_1.io_cpu_execute_args_way
TOP.VexRiscv.dataCache_1.io_cpu_execute_args_wr
TOP.VexRiscv.dataCache_1.io_cpu_execute_isValid
@22
TOP.VexRiscv.dataCache_1.io_mem_cmd_payload_address[31:0]
TOP.VexRiscv.dataCache_1.io_mem_cmd_payload_data[31:0]
TOP.VexRiscv.dataCache_1.io_mem_cmd_payload_length[3:0]
TOP.VexRiscv.dataCache_1.io_mem_cmd_payload_mask[3:0]
@28
TOP.VexRiscv.dataCache_1.io_mem_cmd_payload_wr
TOP.VexRiscv.dataCache_1.io_mem_cmd_ready
TOP.VexRiscv.dataCache_1.io_mem_cmd_valid
@22
TOP.VexRiscv.dataCache_1.victim_request_payload_address[31:0]
@28
TOP.VexRiscv.dataCache_1.victim_request_ready
TOP.VexRiscv.dataCache_1.victim_request_valid
[pattern_trace] 1
[pattern_trace] 0

View File

@ -591,7 +591,7 @@ public:
virtual void preCycle(){
if (top->dBus_cmd_valid && top->dBus_cmd_ready) {
if(pendingCount == 0){
pendingCount = top->dBus_cmd_payload_length;
pendingCount = top->dBus_cmd_payload_length+1;
address = top->dBus_cmd_payload_address;
wr = top->dBus_cmd_payload_wr;
}
@ -1214,7 +1214,7 @@ int main(int argc, char **argv, char **env) {
w.loadHex("../../resources/hex/debugPluginExternal.hex");
w.noInstructionReadCheck();
#if defined(TRACE) || defined(TRACE_ACCESS)
//w.setCyclesPerSecond(5e3);
w.setCyclesPerSecond(5e3);
printf("Speed reduced 5Khz\n");
#endif
w.run(1e9);

View File

@ -1,10 +1,10 @@
IBUS=IBUS_SIMPLE
DBUS=DBUS_SIMPLE
IBUS=IBUS_CACHED
DBUS=DBUS_CACHED
TRACE?=no
TRACE_ACCESS?=no
TRACE_START=0
CSR=yes
MMU=no
MMU=yes
DEBUG_PLUGIN=yes
DEBUG_PLUGIN_EXTERNAL?=no
DHRYSTONE=yes