MMU implemented

Datacached using MMU implemented
It compile, but nothing is tested
This commit is contained in:
Charles Papon 2017-04-28 16:41:23 +02:00
parent ba2ca77114
commit 010ba568f0
7 changed files with 109 additions and 53 deletions

View File

@ -29,6 +29,7 @@ trait Pipeline {
} }
def build(): Unit ={ def build(): Unit ={
plugins.foreach(_.pipeline = this.asInstanceOf[T])
plugins.foreach(_.setup(this.asInstanceOf[T])) plugins.foreach(_.setup(this.asInstanceOf[T]))
//Build plugins //Build plugins

View File

@ -79,7 +79,7 @@ class BranchPlugin(earlyBranch : Boolean,
} }
override def build(pipeline: VexRiscv): Unit = prediction match { override def build(pipeline: VexRiscv): Unit = prediction match {
case NONE => buildWithoutPrediction(pipeline) case `NONE` => buildWithoutPrediction(pipeline)
case `STATIC` => buildWithPrediction(pipeline) case `STATIC` => buildWithPrediction(pipeline)
case `DYNAMIC` => buildWithPrediction(pipeline) case `DYNAMIC` => buildWithPrediction(pipeline)
} }

View File

@ -1,7 +1,7 @@
package SpinalRiscv.Plugin package SpinalRiscv.Plugin
import SpinalRiscv.Riscv._ import SpinalRiscv.Riscv._
import SpinalRiscv.{Stageable, DecoderService, Riscv, VexRiscv} import SpinalRiscv._
import spinal.core._ import spinal.core._
import spinal.lib._ import spinal.lib._
@ -12,17 +12,20 @@ case class DataCacheConfig( cacheSize : Int,
addressWidth : Int, addressWidth : Int,
cpuDataWidth : Int, cpuDataWidth : Int,
memDataWidth : Int, memDataWidth : Int,
catchAccessFault : Boolean = false){ catchAccessFault : Boolean = false,
tagSizeShift : Int = 0){ //Used to force infering ram
def burstSize = bytePerLine*8/memDataWidth def burstSize = bytePerLine*8/memDataWidth
val burstLength = bytePerLine/(memDataWidth/8) val burstLength = bytePerLine/(memDataWidth/8)
assert(catchAccessFault == false) assert(catchAccessFault == false)
} }
case class DataMmuConfig(dTlbSize : Int)
class DBusCachedPlugin(config : DataCacheConfig) extends Plugin[VexRiscv]{
class DBusCachedPlugin(config : DataCacheConfig, mmuConfig : DataMmuConfig = null) extends Plugin[VexRiscv]{
import config._ import config._
var dBus : DataCacheMemBus = null var dBus : DataCacheMemBus = null
var mmuBus : MemoryTranslatorBus = null
object MEMORY_ENABLE extends Stageable(Bool) object MEMORY_ENABLE extends Stageable(Bool)
object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits)) object MEMORY_ADDRESS_LOW extends Stageable(UInt(2 bits))
@ -56,6 +59,9 @@ class DBusCachedPlugin(config : DataCacheConfig) extends Plugin[VexRiscv]{
List(LB, LH, LW, LBU, LHU, LWU).map(_ -> loadActions) ++ List(LB, LH, LW, LBU, LHU, LWU).map(_ -> loadActions) ++
List(SB, SH, SW).map(_ -> storeActions) List(SB, SH, SW).map(_ -> storeActions)
) )
if(mmuConfig != null)
mmuBus = pipeline.service(classOf[MemoryTranslator]).newTranslationPort(pipeline.memory,mmuConfig.dTlbSize)
} }
override def build(pipeline: VexRiscv): Unit = { override def build(pipeline: VexRiscv): Unit = {
@ -98,6 +104,15 @@ class DBusCachedPlugin(config : DataCacheConfig) extends Plugin[VexRiscv]{
import memory._ import memory._
cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE) cache.io.cpu.memory.isValid := arbitration.isValid && input(MEMORY_ENABLE)
cache.io.cpu.memory.isStuck := arbitration.isStuck 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
}
} }
writeBack plug new Area{ writeBack plug new Area{
@ -236,9 +251,12 @@ case class DataCacheCpuExecuteArgs(p : DataCacheConfig) extends Bundle{
case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSlave{ case class DataCacheCpuMemory(p : DataCacheConfig) extends Bundle with IMasterSlave{
val isValid = Bool val isValid = Bool
val isStuck = Bool val isStuck = Bool
val isRemoved = Bool
val mmuBus = MemoryTranslatorBus()
override def asMaster(): Unit = { override def asMaster(): Unit = {
out(isValid, isStuck) out(isValid, isStuck, isRemoved)
slave(mmuBus)
} }
} }
@ -435,7 +453,7 @@ class DataCache(p : DataCacheConfig) extends Component{
val request = requestIn.stage() //TODO FMAX half pipe ? val request = requestIn.stage() //TODO FMAX half pipe ?
request.ready := False request.ready := False
val buffer = Mem(Bits(p.memDataWidth bits),memTransactionPerLine << 1) // WARNING << 1 could resolve cyclone II issue, //.add(new AttributeString("ramstyle","M4K")) val buffer = Mem(Bits(p.memDataWidth bits),memTransactionPerLine << tagSizeShift) // WARNING << tagSizeShift could resolve cyclone II issue, //.add(new AttributeString("ramstyle","M4K"))
//Send line read commands to fill the buffer //Send line read commands to fill the buffer
val readLineCmdCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0) val readLineCmdCounter = Reg(UInt(log2Up(memTransactionPerLine + 1) bits)) init(0)
@ -513,21 +531,23 @@ class DataCache(p : DataCacheConfig) extends Component{
val stageA = new Area{ val stageA = new Area{
val request = RegNextWhen(io.cpu.execute.args, !io.cpu.memory.isStuck) val request = RegNextWhen(io.cpu.execute.args, !io.cpu.memory.isStuck)
io.cpu.memory.mmuBus.cmd.isValid := io.cpu.memory.isValid //TODO filter request kind
io.cpu.memory.mmuBus.cmd.virtualAddress := request.address
} }
val stageB = new Area { val stageB = new Area {
io.flushDone := False io.flushDone := False
val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck) val request = RegNextWhen(stageA.request, !io.cpu.writeBack.isStuck)
val mmuRsp = RegNextWhen(io.cpu.memory.mmuBus.rsp, !io.cpu.writeBack.isStuck)
// val waysHit = RegNextWhen(way.tagReadRspTwoRegIn.used && stageA.request.address(tagRange) === way.tagReadRspTwoRegIn.address,!io.cpu.writeBack.isStuck) //Manual retiming // val waysHit = RegNextWhen(way.tagReadRspTwoRegIn.used && stageA.mmuRsp.physicalAddress(tagRange) === way.tagReadRspTwoRegIn.address,!io.cpu.writeBack.isStuck) //Manual retiming
val waysHit = way.tagReadRspTwo.used && request.address(tagRange) === way.tagReadRspTwo.address val waysHit = way.tagReadRspTwo.used && mmuRsp.physicalAddress(tagRange) === way.tagReadRspTwo.address
//Evict the cache after reset //Evict the cache after reset
val requestValid = io.cpu.writeBack.isValid || RegNextWhen(False, !io.cpu.writeBack.isStuck, True) val requestValid = io.cpu.writeBack.isValid || RegNextWhen(False, !io.cpu.writeBack.isStuck, True)
request.kind init(DataCacheCpuCmdKind.EVICT) request.kind init(DataCacheCpuCmdKind.EVICT)
request.all init(True) request.all init(True)
request.address init(0) mmuRsp.physicalAddress init(0)
io.cpu.writeBack.haltIt := requestValid io.cpu.writeBack.haltIt := requestValid
@ -551,17 +571,17 @@ class DataCache(p : DataCacheConfig) extends Component{
is(EVICT){ is(EVICT){
when(request.all){ when(request.all){
tagsWriteCmd.valid := True tagsWriteCmd.valid := True
tagsWriteCmd.address := request.address(lineRange) tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
tagsWriteCmd.data.used := False tagsWriteCmd.data.used := False
when(request.address(lineRange) =/= lineCount-1){ when(mmuRsp.physicalAddress(lineRange) =/= lineCount-1){
request.address.getDrivingReg(lineRange) := request.address(lineRange) + 1 mmuRsp.physicalAddress.getDrivingReg(lineRange) := mmuRsp.physicalAddress(lineRange) + 1
}otherwise{ }otherwise{
io.cpu.writeBack.haltIt := False io.cpu.writeBack.haltIt := False
} }
}otherwise{ }otherwise{
when(waysHit) { when(waysHit) {
tagsWriteCmd.valid := True tagsWriteCmd.valid := True
tagsWriteCmd.address := request.address(lineRange) tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
tagsWriteCmd.data.used := False tagsWriteCmd.data.used := False
} }
io.cpu.writeBack.haltIt := False io.cpu.writeBack.haltIt := False
@ -572,15 +592,15 @@ class DataCache(p : DataCacheConfig) extends Component{
// when(!flushAllState){ // when(!flushAllState){
// victim.requestIn.valid := waysRead(0).tag.used && waysRead(0).tag.dirty // victim.requestIn.valid := waysRead(0).tag.used && waysRead(0).tag.dirty
// victim.requestIn.way := writebackWayId // victim.requestIn.way := writebackWayId
// victim.requestIn.address := writebackWayInfo.address @@ request.address(lineRange) @@ U((lineRange.low - 1 downto 0) -> false) // victim.requestIn.address := writebackWayInfo.address @@ mmuRsp.physicalAddress(lineRange) @@ U((lineRange.low - 1 downto 0) -> false)
// //
// tagsWriteCmd.way := writebackWayId // tagsWriteCmd.way := writebackWayId
// tagsWriteCmd.address := request.address(lineRange) // tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
// tagsWriteCmd.data.used := False // tagsWriteCmd.data.used := False
// //
// when(!victim.requestIn.isStall) { // when(!victim.requestIn.isStall) {
// request.address.getDrivingReg(lineRange) := request.address(lineRange) + 1 // mmuRsp.physicalAddress.getDrivingReg(lineRange) := mmuRsp.physicalAddress(lineRange) + 1
// flushAllDone := request.address(lineRange) === lineCount-1 // flushAllDone := mmuRsp.physicalAddress(lineRange) === lineCount-1
// flushAllState := True // flushAllState := True
// tagsWriteCmd.valid := True // tagsWriteCmd.valid := True
// } // }
@ -597,11 +617,11 @@ class DataCache(p : DataCacheConfig) extends Component{
// //
// victim.requestIn.valid := True // victim.requestIn.valid := True
// victim.requestIn.way := writebackWayId // victim.requestIn.way := writebackWayId
// victim.requestIn.address := writebackWayInfo.address @@ request.address(lineRange) @@ U((lineRange.low - 1 downto 0) -> false) // victim.requestIn.address := writebackWayInfo.address @@ mmuRsp.physicalAddress(lineRange) @@ U((lineRange.low - 1 downto 0) -> false)
// //
// tagsWriteCmd.valid := victim.requestIn.ready // tagsWriteCmd.valid := victim.requestIn.ready
// tagsWriteCmd.way := writebackWayId // tagsWriteCmd.way := writebackWayId
// tagsWriteCmd.address := request.address(lineRange) // tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
// tagsWriteCmd.data.used := False // tagsWriteCmd.data.used := False
// } otherwise{ // } otherwise{
// io.cpu.memory.haltIt := False // io.cpu.memory.haltIt := False
@ -615,7 +635,7 @@ class DataCache(p : DataCacheConfig) extends Component{
val memCmdSent = RegInit(False) val memCmdSent = RegInit(False)
when(!victim.request.valid) { //Avoid mixing memory request while victim is pending when(!victim.request.valid) { //Avoid mixing memory request while victim is pending
io.mem.cmd.wr := request.wr io.mem.cmd.wr := request.wr
io.mem.cmd.address := request.address(tagRange.high downto wordRange.low) @@ U(0,wordRange.low bit) io.mem.cmd.address := mmuRsp.physicalAddress(tagRange.high downto wordRange.low) @@ U(0,wordRange.low bit)
io.mem.cmd.mask := request.mask io.mem.cmd.mask := request.mask
io.mem.cmd.data := request.data io.mem.cmd.data := request.data
io.mem.cmd.length := 1 io.mem.cmd.length := 1
@ -632,20 +652,20 @@ class DataCache(p : DataCacheConfig) extends Component{
when(waysHit || !loadingNotDone){ when(waysHit || !loadingNotDone){
io.cpu.writeBack.haltIt := False io.cpu.writeBack.haltIt := False
dataWriteCmd.valid := request.wr dataWriteCmd.valid := request.wr
dataWriteCmd.address := request.address(lineRange.high downto wordRange.low) dataWriteCmd.address := mmuRsp.physicalAddress(lineRange.high downto wordRange.low)
dataWriteCmd.data := request.data dataWriteCmd.data := request.data
dataWriteCmd.mask := request.mask dataWriteCmd.mask := request.mask
tagsWriteCmd.valid := !loadingNotDone || request.wr tagsWriteCmd.valid := !loadingNotDone || request.wr
tagsWriteCmd.address := request.address(lineRange) tagsWriteCmd.address := mmuRsp.physicalAddress(lineRange)
tagsWriteCmd.data.used := True tagsWriteCmd.data.used := True
tagsWriteCmd.data.dirty := request.wr tagsWriteCmd.data.dirty := request.wr
tagsWriteCmd.data.address := request.address(tagRange) tagsWriteCmd.data.address := mmuRsp.physicalAddress(tagRange)
} otherwise { } otherwise {
val victimRequired = way.tagReadRspTwo.used && way.tagReadRspTwo.dirty val victimRequired = way.tagReadRspTwo.used && way.tagReadRspTwo.dirty
loaderValid := loadingNotDone && !(victimNotSent && victim.request.isStall) //Additional condition used to be sure of that all previous victim are written into the RAM loaderValid := loadingNotDone && !(victimNotSent && victim.request.isStall) //Additional condition used to be sure of that all previous victim are written into the RAM
victim.requestIn.valid := victimRequired && victimNotSent victim.requestIn.valid := victimRequired && victimNotSent
victim.requestIn.address := way.tagReadRspTwo.address @@ request.address(lineRange) @@ U((lineRange.low - 1 downto 0) -> false) victim.requestIn.address := way.tagReadRspTwo.address @@ mmuRsp.physicalAddress(lineRange) @@ U((lineRange.low - 1 downto 0) -> false)
} }
} }
} }
@ -660,7 +680,7 @@ class DataCache(p : DataCacheConfig) extends Component{
//The whole life of a loading task, the corresponding manager request is present //The whole life of a loading task, the corresponding manager request is present
val loader = new Area{ val loader = new Area{
val valid = RegNext(stageB.loaderValid) init(False) val valid = RegNext(stageB.loaderValid) init(False)
val baseAddress = stageB.request.address val baseAddress = stageB.mmuRsp.physicalAddress
val memCmdSent = RegInit(False) val memCmdSent = RegInit(False)
when(valid && !memCmdSent) { when(valid && !memCmdSent) {

View File

@ -7,6 +7,7 @@ import spinal.core.Area
* Created by PIC32F_USER on 03/03/2017. * Created by PIC32F_USER on 03/03/2017.
*/ */
trait Plugin[T <: Pipeline] { trait Plugin[T <: Pipeline] {
var pipeline : T = null.asInstanceOf[T]
def getName() = this.getClass.getSimpleName.replace("$","") def getName() = this.getClass.getSimpleName.replace("$","")
def setup(pipeline: T) : Unit = {} def setup(pipeline: T) : Unit = {}

View File

@ -21,3 +21,26 @@ case class ExceptionCause() extends Bundle{
trait ExceptionService{ trait ExceptionService{
def newExceptionPort(stage : Stage, priority : Int = 0) : Flow[ExceptionCause] def newExceptionPort(stage : Stage, priority : Int = 0) : Flow[ExceptionCause]
} }
case class MemoryTranslatorCmd() extends Bundle{
val isValid = Bool
val virtualAddress = UInt(32 bits)
}
case class MemoryTranslatorRsp() extends Bundle{
val physicalAddress = UInt(32 bits)
val allowRead, allowWrite, allowExecute = Bool
}
case class MemoryTranslatorBus() extends Bundle with IMasterSlave{
val cmd = MemoryTranslatorCmd()
val rsp = MemoryTranslatorRsp()
override def asMaster() : Unit = {
out(cmd)
in(rsp)
}
}
trait MemoryTranslator{
def newTranslationPort(stage : Stage, cacheSize : Int) : MemoryTranslatorBus
}

View File

@ -203,24 +203,24 @@ object TopLevel {
configTest.plugins ++= List( configTest.plugins ++= List(
new PcManagerSimplePlugin(0x00000000l, true), new PcManagerSimplePlugin(0x00000000l, true),
new IBusSimplePlugin( // new IBusSimplePlugin(
interfaceKeepData = true, // interfaceKeepData = true,
catchAccessFault = false // catchAccessFault = false
),
// new IBusCachedPlugin(
// config = InstructionCacheConfig(
// cacheSize = 4096,
// bytePerLine =32,
// wayCount = 1,
// wrappedMemAccess = true,
// addressWidth = 32,
// cpuDataWidth = 32,
// memDataWidth = 32,
// catchAccessFault = false,
// asyncTagMemory = false,
// twoStageLogic = true
// )
// ), // ),
new IBusCachedPlugin(
config = InstructionCacheConfig(
cacheSize = 4096,
bytePerLine =32,
wayCount = 1,
wrappedMemAccess = true,
addressWidth = 32,
cpuDataWidth = 32,
memDataWidth = 32,
catchAccessFault = false,
asyncTagMemory = false,
twoStageLogic = true
)
),
// new DBusSimplePlugin( // new DBusSimplePlugin(
// catchAddressMisaligned = false, // catchAddressMisaligned = false,
@ -239,15 +239,26 @@ object TopLevel {
// ), // ),
new DBusCachedPlugin( new DBusCachedPlugin(
config = new DataCacheConfig( config = new DataCacheConfig(
cacheSize = 128, cacheSize = 4096,
bytePerLine = 32, bytePerLine = 32,
wayCount = 1, wayCount = 1,
addressWidth = 32, addressWidth = 32,
cpuDataWidth = 32, cpuDataWidth = 32,
memDataWidth = 32, memDataWidth = 32,
catchAccessFault = false catchAccessFault = false,
tagSizeShift = 2
),
mmuConfig = DataMmuConfig(
dTlbSize = 6
) )
), ),
new MemoryTranslatorPlugin(
tlbSize = 32,
exceptionCode = 13,
mmuRange = !_(31)
),
new MachineCsr(csrConfigAll),
new DecoderSimplePlugin( new DecoderSimplePlugin(
catchIllegalInstruction = false catchIllegalInstruction = false
), ),
@ -264,10 +275,10 @@ object TopLevel {
// new HazardSimplePlugin(true, true, true, true), // new HazardSimplePlugin(true, true, true, true),
// new HazardSimplePlugin(false, true, false, true), // new HazardSimplePlugin(false, true, false, true),
new HazardSimplePlugin( new HazardSimplePlugin(
bypassExecute = false, bypassExecute = true,
bypassMemory = false, bypassMemory = true,
bypassWriteBack = false, bypassWriteBack = true,
bypassWriteBackBuffer = false, bypassWriteBackBuffer = true,
pessimisticUseSrc = false, pessimisticUseSrc = false,
pessimisticWriteRegFile = false, pessimisticWriteRegFile = false,
pessimisticAddressMatch = false pessimisticAddressMatch = false
@ -282,9 +293,9 @@ object TopLevel {
) )
) )
val toplevel = new VexRiscv(configFull) // val toplevel = new VexRiscv(configFull)
// val toplevel = new VexRiscv(configLight) // val toplevel = new VexRiscv(configLight)
// val toplevel = new VexRiscv(configTest) val toplevel = new VexRiscv(configTest)
toplevel.decode.input(toplevel.config.INSTRUCTION).addAttribute(Verilator.public) toplevel.decode.input(toplevel.config.INSTRUCTION).addAttribute(Verilator.public)
toplevel.decode.input(toplevel.config.PC).addAttribute(Verilator.public) toplevel.decode.input(toplevel.config.PC).addAttribute(Verilator.public)
toplevel.decode.arbitration.isValid.addAttribute(Verilator.public) toplevel.decode.arbitration.isValid.addAttribute(Verilator.public)

View File

@ -1,4 +1,4 @@
IBUS=IBUS_SIMPLE IBUS=IBUS_CACHED
DBUS=DBUS_CACHED DBUS=DBUS_CACHED
TRACE=no TRACE=no
TRACE_START=0 TRACE_START=0