hardware refilled MmuPlugin wip

This commit is contained in:
Dolu1990 2019-03-17 21:06:47 +01:00
parent 03663ce91a
commit ffa489d211
3 changed files with 224 additions and 2 deletions

View File

@ -105,6 +105,7 @@ object Riscv{
def FENCE = M"-----------------000-----0001111" def FENCE = M"-----------------000-----0001111"
def FENCE_I = M"-----------------001-----0001111" def FENCE_I = M"-----------------001-----0001111"
def SFENCE_VMA = M"0001001----------000000001110011"
object CSR{ object CSR{
def MVENDORID = 0xF11 // MRO Vendor ID. def MVENDORID = 0xF11 // MRO Vendor ID.

View File

@ -65,8 +65,8 @@ case class MemoryTranslatorRsp() extends Bundle{
val physicalAddress = UInt(32 bits) val physicalAddress = UInt(32 bits)
val isIoAccess = Bool val isIoAccess = Bool
val allowRead, allowWrite, allowExecute, allowUser = Bool val allowRead, allowWrite, allowExecute, allowUser = Bool
val miss = Bool val exception = Bool
val hit = Bool val refilling = Bool
} }
case class MemoryTranslatorBus() extends Bundle with IMasterSlave{ case class MemoryTranslatorBus() extends Bundle with IMasterSlave{

View File

@ -0,0 +1,221 @@
package vexriscv.plugin
import vexriscv.{VexRiscv, _}
import spinal.core._
import spinal.lib._
import scala.collection.mutable.ArrayBuffer
case class DBusAccessCmd() extends Bundle {
val address = UInt(32 bits)
val size = UInt(2 bits)
val write = Bool
val writeData = Bits(32 bits)
val writeMask = Bits(4 bits)
}
case class DBusAccessRsp() extends Bundle {
val data = Bits(32 bits)
val error = Bool()
}
case class DBusAccess() extends Bundle {
val cmd = Stream(DBusAccessCmd())
val rsp = Flow(DBusAccessRsp())
}
object MmuPort{
val PRIORITY_DATA = 1
val PRIORITY_INSTRUCTION = 0
}
case class MmuPort(bus : MemoryTranslatorBus, priority : Int, args : MmuPortConfig, id : Int/*, exceptionBus: Flow[ExceptionCause]*/)
case class MmuPortConfig(portTlbSize : Int)
class MmuPlugin(virtualRange : UInt => Bool,
ioRange : UInt => Bool,
allowUserIo : Boolean) extends Plugin[VexRiscv] with MemoryTranslator {
var dBus : DBusAccess = null
val portsInfo = ArrayBuffer[MmuPort]()
override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = {
// val exceptionBus = pipeline.service(classOf[ExceptionService]).newExceptionPort(stage)
val port = MmuPort(MemoryTranslatorBus(),priority,args.asInstanceOf[MmuPortConfig], portsInfo.length /*,exceptionBus*/)
portsInfo += port
port.bus
}
object IS_SFENCE_VMA extends Stageable(Bool)
override def setup(pipeline: VexRiscv): Unit = {
import Riscv._
import pipeline.config._
val decoderService = pipeline.service(classOf[DecoderService])
decoderService.addDefault(IS_SFENCE_VMA, False)
decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA -> True))
dBus = ???
}
override def build(pipeline: VexRiscv): Unit = {
import pipeline._
import pipeline.config._
import Riscv._
val csrService = pipeline.service(classOf[CsrInterface])
//Sorted by priority
val sortedPortsInfo = portsInfo.sortWith((a,b) => a.priority > b.priority)
case class CacheLine() extends Bundle {
val valid, exception = Bool
val virtualAddress = UInt(20 bits)
val physicalAddress = UInt(20 bits)
val allowRead, allowWrite, allowExecute, allowUser = Bool
def init = {
valid init (False)
this
}
}
val core = pipeline plug new Area {
val ports = for (port <- sortedPortsInfo yield new Area {
val id = port.id
val cache = Vec(Reg(CacheLine()) init, port.args.portTlbSize)
val cacheHits = cache.map(line => line.valid && line.virtualAddress === port.bus.cmd.virtualAddress(31 downto 12))
val cacheHit = cacheHits.asBits.orR
val cacheLine = MuxOH(cacheHits, cache)
val isInMmuRange = virtualRange(port.bus.cmd.virtualAddress) && !port.bus.cmd.bypassTranslation
val entryToReplace = Counter(port.args.portTlbSize)
when(isInMmuRange) {
port.bus.rsp.physicalAddress := cacheLine.physicalAddress @@ port.bus.cmd.virtualAddress(11 downto 0)
port.bus.rsp.allowRead := cacheLine.allowRead
port.bus.rsp.allowWrite := cacheLine.allowWrite
port.bus.rsp.allowExecute := cacheLine.allowExecute
port.bus.rsp.allowUser := cacheLine.allowUser
port.bus.rsp.exception := cacheHit && cacheLine.exception
port.bus.rsp.refilling := !cacheHit
} otherwise {
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 := Bool(allowUserIo)
port.bus.rsp.exception := False
port.bus.rsp.refilling := False
}
port.bus.rsp.isIoAccess := ioRange(port.bus.rsp.physicalAddress)
}
val shared = new Area {
val busy = Reg(Bool) init(False)
val satp = new Bundle {
val mode = Bool()
val ppn = UInt(20 bits)
}
csrService.rw(CSR.SATP, 31 -> satp.mode, 0 -> satp.ppn) //TODO write only ?
val State = new SpinalEnum{
val IDLE, L1_CMD, L1_RSP, L0_CMD, L0_RSP = newElement()
}
val state = RegInit(State.IDLE)
val vpn1, vpn0 = Reg(UInt(10 bits))
val portId = Reg(UInt(log2Up(portsInfo.length) bits))
case class PTE() extends Bundle {
val V, R, W ,X, U, G, A, D = Bool()
val RSW = Bits(2 bits)
val PPN0 = UInt(10 bits)
val PPN1 = UInt(12 bits)
}
val dBusRsp = new Area{
val pte = PTE()
pte.assignFromBits(dBus.rsp.data)
val exception = !pte.V || (!pte.R && pte.W) || dBus.rsp.error
val leaf = pte.R || pte.X
}
val pteBuffer = RegNextWhen(dBusRsp.pte, dBus.rsp.valid)
dBus.cmd.write := False
dBus.cmd.size := 2
dBus.cmd.address.assignDontCare()
dBus.cmd.writeData.assignDontCare()
dBus.cmd.writeMask.assignDontCare()
switch(state){
is(State.IDLE){
for(port <- portsInfo.sortBy(_.priority)){
when(port.bus.cmd.isValid && port.bus.rsp.refilling){
busy := True
vpn1 := port.bus.cmd.virtualAddress(31 downto 22)
vpn0 := port.bus.cmd.virtualAddress(21 downto 12)
portId := port.id
state := State.L1_CMD
}
}
}
is(State.L1_CMD){
dBus.cmd.valid := True
dBus.cmd.address := satp.ppn @@ vpn1 @@ U"00"
when(dBus.cmd.ready){
state := State.L1_RSP
}
}
is(State.L1_RSP){
when(dBus.rsp.valid){
when(dBusRsp.leaf || dBusRsp.exception){
state := State.IDLE
} otherwise {
state := State.L0_CMD
}
}
}
is(State.L0_CMD){
dBus.cmd.valid := True
dBus.cmd.address := pteBuffer.PPN1(9 downto 0) @@ pteBuffer.PPN0 @@ vpn0 @@ U"00"
when(dBus.cmd.ready){
state := State.L0_RSP
}
}
is(State.L0_RSP){
when(dBus.rsp.valid) {
state := State.IDLE
}
}
}
when(dBus.rsp.valid && (dBusRsp.leaf || dBusRsp.exception)){
for(port <- ports){
when(portId === port.id) {
port.entryToReplace.increment()
for ((line, lineId) <- port.cache.zipWithIndex) {
when(port.entryToReplace === lineId){
line.valid := True
line.exception := dBusRsp.exception
line.virtualAddress := vpn1 @@ vpn0
line.physicalAddress := dBusRsp.pte.PPN1(9 downto 0) @@ dBusRsp.pte.PPN0
line.allowRead := dBusRsp.pte.R
line.allowWrite := dBusRsp.pte.W
line.allowExecute := dBusRsp.pte.X
line.allowUser := dBusRsp.pte.U
}
}
}
}
}
}
}
execute plug new Area{
import execute._
val tlbWriteBuffer = Reg(UInt(20 bits))
when(arbitration.isFiring && input(IS_SFENCE_VMA)){
for(port <- core.ports; line <- port.cache) line.valid := False //Assume that the instruction already fetched into the pipeline are ok
}
}
}
}