Got the new MMU design to pass simple tests #60

This commit is contained in:
Dolu1990 2019-03-22 01:10:17 +01:00
parent ea56481ead
commit af2acbd46e
15 changed files with 15949 additions and 76 deletions

View File

@ -44,9 +44,16 @@ trait Pipeline {
plugins.foreach(_.pipeline = this.asInstanceOf[T])
plugins.foreach(_.setup(this.asInstanceOf[T]))
plugins.foreach{ p =>
p.parentScope = Component.current.dslBody //Put the given plugin as a child of the current component
p.reflectNames()
}
//Build plugins
plugins.foreach(_.build(this.asInstanceOf[T]))
//Interconnect stages
class KeyInfo{
var insertStageId = Int.MaxValue

View File

@ -170,7 +170,7 @@ object LinuxGen {
)
)
if(withMmu) config.plugins += new MmuPlugin(
virtualRange = _(31 downto 28) === 0xC,
virtualRange = a => True,
ioRange = _(31 downto 28) === 0xF,
allowUserIo = true
)

View File

@ -109,7 +109,7 @@ object CsrPluginConfig{
sbadaddrAccess = CsrAccess.READ_WRITE,
scycleAccess = CsrAccess.READ_WRITE,
sinstretAccess = CsrAccess.READ_WRITE,
satpAccess = CsrAccess.READ_WRITE,
satpAccess = CsrAccess.NONE, //Implemented into the MMU plugin
medelegAccess = CsrAccess.READ_WRITE,
midelegAccess = CsrAccess.READ_WRITE,
pipelineCsrRead = false,
@ -643,7 +643,7 @@ class CsrPlugin(config: CsrPluginConfig) extends Plugin[VexRiscv] with Exception
})
val sortedByStage = groupedByStage.sortWith((a, b) => pipeline.indexOf(a.stage) < pipeline.indexOf(b.stage))
sortedByStage.zipWithIndex.foreach(e => e._1.port.setName(e._1.stage.getName() + "_exception_agregat"))
// sortedByStage.zipWithIndex.foreach(e => e._1.port.setName(e._1.stage.getName() + "_exception_agregat"))
exceptionValids := exceptionValidsRegs
for(portInfo <- sortedByStage; port = portInfo.port ; stage = portInfo.stage; stageId = indexOf(portInfo.stage)) {
when(port.valid) {

View File

@ -223,7 +223,7 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
var redoBranch : Flow[UInt] = null
val catchSomething = catchAccessFault || catchAddressMisaligned || memoryTranslatorPortConfig != null
var dBusAccess : DBusAccess = null
@dontName var dBusAccess : DBusAccess = null
override def newDBusAccess(): DBusAccess = {
assert(dBusAccess == null)
dBusAccess = DBusAccess()
@ -383,6 +383,8 @@ class DBusSimplePlugin(catchAddressMisaligned : Boolean = false,
if(catchSomething) memoryExceptionPort.valid := False
if(memoryTranslatorPortConfig != null) redoBranch.valid := False
}
arbitration.flushAll setWhen(redoBranch.valid)
}

View File

@ -607,8 +607,7 @@ abstract class IBusFetcherImpl(val resetVector : BigInt,
}
def stageXToIBusRsp[T <: Data](stage : Any, input : T): (T) ={
iBusRsp.stages.dropWhile(_ != stage).foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready))
iBusRsp.stages.dropWhile(_ != stage).tail.foldLeft(input)((data,stage) => RegNextWhen(data, stage.output.ready))
}
}

View File

@ -305,6 +305,8 @@ class IBusSimplePlugin(resetVector : BigInt,
redoBranch.payload := stages.last.input.payload
}
decode.arbitration.flushAll setWhen(redoBranch.valid)
if(catchSomething){
decodeExceptionPort.code.assignDontCare()
decodeExceptionPort.badAddr := join.pc //TODO Should it be the physical address insted ?
@ -315,7 +317,7 @@ class IBusSimplePlugin(resetVector : BigInt,
}
if(memoryTranslatorPortConfig != null) {
val privilegeService = pipeline.serviceElse(classOf[PrivilegeService], PrivilegeServiceDefault())
when(stages.last.input.valid && (mmu.joinCtx.exception || !mmu.joinCtx.allowExecute || (!mmu.joinCtx.allowUser && privilegeService.isUser(decode)))){
when(stages.last.input.valid && !mmu.joinCtx.refilling && (mmu.joinCtx.exception || !mmu.joinCtx.allowExecute || (!mmu.joinCtx.allowUser && privilegeService.isUser(decode)))){
decodeExceptionPort.code := 12
exceptionDetected := True
}

View File

@ -42,7 +42,7 @@ class MmuPlugin(virtualRange : UInt => Bool,
allowUserIo : Boolean,
allowMachineModeMmu : Boolean = false) extends Plugin[VexRiscv] with MemoryTranslator {
var dBus : DBusAccess = null
var dBusAccess : DBusAccess = null
val portsInfo = ArrayBuffer[MmuPort]()
override def newTranslationPort(priority : Int,args : Any): MemoryTranslatorBus = {
@ -61,7 +61,7 @@ class MmuPlugin(virtualRange : UInt => Bool,
decoderService.add(SFENCE_VMA, List(IS_SFENCE_VMA -> True))
dBus = pipeline.service(classOf[DBusAccessService]).newDBusAccess()
dBusAccess = pipeline.service(classOf[DBusAccessService]).newDBusAccess()
}
override def build(pipeline: VexRiscv): Unit = {
@ -142,19 +142,19 @@ class MmuPlugin(virtualRange : UInt => Bool,
}
val dBusRsp = new Area{
val pte = PTE()
pte.assignFromBits(dBus.rsp.data)
val exception = !pte.V || (!pte.R && pte.W) || dBus.rsp.error
pte.assignFromBits(dBusAccess.rsp.data)
val exception = !pte.V || (!pte.R && pte.W) || dBusAccess.rsp.error
val leaf = pte.R || pte.X
}
val pteBuffer = RegNextWhen(dBusRsp.pte, dBus.rsp.valid)
val pteBuffer = RegNextWhen(dBusRsp.pte, dBusAccess.rsp.valid)
dBus.cmd.valid := False
dBus.cmd.write := False
dBus.cmd.size := 2
dBus.cmd.address.assignDontCare()
dBus.cmd.data.assignDontCare()
dBus.cmd.writeMask.assignDontCare()
dBusAccess.cmd.valid := False
dBusAccess.cmd.write := False
dBusAccess.cmd.size := 2
dBusAccess.cmd.address.assignDontCare()
dBusAccess.cmd.data.assignDontCare()
dBusAccess.cmd.writeMask.assignDontCare()
switch(state){
is(State.IDLE){
for(port <- portsInfo.sortBy(_.priority)){
@ -168,14 +168,14 @@ class MmuPlugin(virtualRange : UInt => Bool,
}
}
is(State.L1_CMD){
dBus.cmd.valid := True
dBus.cmd.address := satp.ppn @@ vpn1 @@ U"00"
when(dBus.cmd.ready){
dBusAccess.cmd.valid := True
dBusAccess.cmd.address := satp.ppn @@ vpn1 @@ U"00"
when(dBusAccess.cmd.ready){
state := State.L1_RSP
}
}
is(State.L1_RSP){
when(dBus.rsp.valid){
when(dBusAccess.rsp.valid){
when(dBusRsp.leaf || dBusRsp.exception){
state := State.IDLE
} otherwise {
@ -184,20 +184,20 @@ class MmuPlugin(virtualRange : UInt => Bool,
}
}
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){
dBusAccess.cmd.valid := True
dBusAccess.cmd.address := pteBuffer.PPN1(9 downto 0) @@ pteBuffer.PPN0 @@ vpn0 @@ U"00"
when(dBusAccess.cmd.ready){
state := State.L0_RSP
}
}
is(State.L0_RSP){
when(dBus.rsp.valid) {
when(dBusAccess.rsp.valid) {
state := State.IDLE
}
}
}
when(dBus.rsp.valid && (dBusRsp.leaf || dBusRsp.exception)){
when(dBusAccess.rsp.valid && (dBusRsp.leaf || dBusRsp.exception)){
for(port <- ports){
when(portId === port.id) {
port.entryToReplace.increment()

View File

@ -1,14 +1,14 @@
package vexriscv.plugin
import vexriscv.{Pipeline, Stage}
import spinal.core.Area
import spinal.core.{Area, Nameable}
/**
* Created by PIC32F_USER on 03/03/2017.
*/
trait Plugin[T <: Pipeline] {
trait Plugin[T <: Pipeline] extends Nameable{
var pipeline : T = null.asInstanceOf[T]
def getName() = this.getClass.getSimpleName.replace("$","")
setName(this.getClass.getSimpleName.replace("$",""))
def setup(pipeline: T) : Unit = {}
def build(pipeline: T) : Unit

4
src/test/cpp/raw/mmu/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.map
*.v
*.elf
*.o

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -20,20 +20,108 @@ _start:
csrw mtvec, x1
csrw stvec, x1
//Test 1
test1: //test ram
li x28, 1
la x1, ROM_2
li x2, 0x27262524
lw x1, 4(x1)
bne x1, x2, fail
//Test 2
test2: //dummy mret
li x28, 2
la x1, test3
csrw mepc, x1
li x1, 0x1800
csrw mstatus, x1
mret
j fail
test3: // jump to supervisor
li x28, 3
li x1, 0x0800
csrw mstatus, x1
la x1, test4
csrw mepc, x1
mret
j fail
test4: //test ram mmu off
li x28, 4
la x1, ROM_3
li x2, 0x37363534
lw x1, 4(x1)
bne x1, x2, fail
test5: //setup MMU
li x28, 5
la x1, MMU_TABLE_0 + 0x800
la x2, MMU_TABLE_1
srli x2, x2, 2
ori x2, x2, 0x11
sw x2, 0(x1)
la x1, MMU_TABLE_1 + 0x000*4
li x2, 0x80000000
srli x2, x2, 2
ori x2, x2, 0x1F
sw x2, 0(x1)
li x28, 5
la x1, MMU_TABLE_0 + 0x900
la x2, MMU_TABLE_2
srli x2, x2, 2
ori x2, x2, 0x11
sw x2, 0(x1)
la x1, MMU_TABLE_2 + 0x00A*4
la x2, ROM_4
srli x2, x2, 2
ori x2, x2, 0x1F
sw x2, 0(x1)
la x1, MMU_TABLE_0
srli x1, x1, 12
li x2, 0x80000000
or x1, x1, x2
csrw satp, x1
test6: //read through MMU !
li x28, 6
li x1, 0x9000A008
li x2, 0x4B4A4948
lw x1, 0(x1)
bne x1, x2, fail
j pass
fail: //x28 => error code
csrwi satp, 0
j failFence
failFence:
li x2, 0xF00FFF24
sw x28, 0(x2)
pass:
csrwi satp, 0
j passFence
passFence:
li x2, 0xF00FFF20
sw x0, 0(x2)
@ -45,3 +133,77 @@ pass:
nop
nop
nop
.align 12
MMU_TABLE_0:
.word 0
.align 12
MMU_TABLE_1:
.word 0
.align 12
MMU_TABLE_2:
.word 0
.align 12
MMU_TABLE_3:
.word 0
.align 12
ROM_0:
.word 0x03020100
.word 0x07060504
.word 0x0B0A0908
.word 0x0F0E0D0C
.align 12
ROM_1:
.word 0x13121110
.word 0x17161514
.word 0x1B1A1918
.word 0x1F1E1D1C
.align 12
ROM_2:
.word 0x23222120
.word 0x27262524
.word 0x2B2A2928
.word 0x2F2E2D2C
.align 12
ROM_3:
.word 0x33323130
.word 0x37363534
.word 0x3B3A3938
.word 0x3F3E3D3C
.align 12
ROM_4:
.word 0x43424140
.word 0x47464544
.word 0x4B4A4948
.word 0x4F4E4D4C
.align 12
ROM_5:
.word 0x53525150
.word 0x57565554
.word 0x5B5A5958
.word 0x5F5E5D5C
.align 12
ROM_6:
.word 0x63626160
.word 0x67666564
.word 0x6B6A6968
.word 0x6F6E6D6C
.align 12
ROM_7:
.word 0x73727170
.word 0x77767574
.word 0x7B7A7978
.word 0x7F7E7D7C

View File

@ -1,7 +1,7 @@
OUTPUT_ARCH( "riscv" )
MEMORY {
onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 8K
onChipRam (W!RX)/*(RX)*/ : ORIGIN = 0x80000000, LENGTH = 1M
}
SECTIONS

View File

@ -289,20 +289,42 @@ public:
union mcause {
uint32_t raw;
struct {
struct __attribute__((packed)) {
uint32_t exceptionCode : 31;
uint32_t interrupt : 1;
};
}__attribute__((packed)) mcause;
} mcause;
union scause {
uint32_t raw;
struct {
struct __attribute__((packed)){
uint32_t exceptionCode : 31;
uint32_t interrupt : 1;
};
}__attribute__((packed)) scause;
} scause;
union satp {
uint32_t raw;
struct __attribute__((packed)){
uint32_t ppn : 22;
uint32_t _x : 9;
uint32_t mode : 1;
};
}satp;
union Tlb {
uint32_t raw;
struct __attribute__((packed)){
uint32_t v : 1;
uint32_t r : 1;
uint32_t w : 1;
uint32_t x : 1;
uint32_t u : 1;
uint32_t _dummy : 5;
uint32_t ppn : 22;
};
};
@ -324,6 +346,7 @@ public:
privilege = 3;
medeleg = 0;
mideleg = 0;
satp.mode = 0;
}
virtual void rfWrite(int32_t address, int32_t data) {
@ -346,6 +369,29 @@ public:
virtual bool dRead(int32_t address, int32_t size, uint32_t *data) = 0;
virtual void dWrite(int32_t address, int32_t size, uint32_t data) = 0;
enum AccessKind {READ,WRITE,EXECUTE};
bool v2p(uint32_t v, uint32_t *p, AccessKind kind){
if(privilege == 3 || satp.mode == 0){
*p = v;
} else {
Tlb tlb;
dRead((satp.ppn << 12) | ((v >> 22) << 2), 4, &tlb.raw);
if(!tlb.v) return true;
if(!tlb.x && !tlb.r && !tlb.w){
dRead((tlb.ppn << 12) | (((v >> 12) & 0x3FF) << 2), 4, &tlb.raw);
if(!tlb.v) return true;
}
if(!tlb.u && privilege == 0) return true;
switch(kind){
case READ: if(!tlb.r) return true; break;
case WRITE: if(!tlb.w) return true; break;
case EXECUTE: if(!tlb.x) return true; break;
}
*p = (tlb.ppn << 12) | (v & 0xFFF);
}
return false;
}
void exception(bool interrupt,int32_t cause) {
exception(interrupt, cause, false, 0);
}
@ -396,6 +442,7 @@ public:
virtual bool csrRead(int32_t csr, uint32_t *value){
if(((csr >> 8) & 0x3) > privilege) return true;
switch(csr){
case MSTATUS: *value = status.raw; break;
case MIP: *value = ip.raw; break;
@ -415,6 +462,7 @@ public:
case STVAL: *value = sbadaddr; break;
case SEPC: *value = sepc; break;
case SSCRATCH: *value = sscratch; break;
case SATP: *value = satp.raw; break;
default: return true; break;
}
return false;
@ -422,6 +470,7 @@ public:
#define maskedWrite(dst, src, mask) dst=(dst & ~mask)|(src & mask);
virtual bool csrWrite(int32_t csr, uint32_t value){
if(((csr >> 8) & 0x3) > privilege) return true;
switch(csr){
case MSTATUS: status.raw = value; break;
case MIP: ip.raw = value; break;
@ -441,6 +490,7 @@ public:
case STVAL: sbadaddr = value; break;
case SEPC: sepc = value; break;
case SSCRATCH: sscratch = value; break;
case SATP: satp.raw = value; break;
default: ilegalInstruction(); return true; break;
}
@ -513,22 +563,26 @@ public:
#define i16_swsp_imm ((iBits(9, 4) << 2) + (iBits(7, 2) << 6))
uint32_t i;
uint32_t u32Buf;
uint32_t pAddr;
if (pc & 2) {
if(iRead(pc - 2, &i)){
if(v2p(pc - 2, &pAddr, EXECUTE)){ exception(0, 12); return; }
if(iRead(pAddr, &i)){
exception(0, 1);
return;
}
i >>= 16;
if (i & 3 == 3) {
uint32_t u32Buf;
if(iRead(pc + 2, &u32Buf)){
if(v2p(pc + 2, &pAddr, EXECUTE)){ exception(0, 12); return; }
if(iRead(pAddr, &u32Buf)){
exception(0, 1);
return;
}
i |= u32Buf << 16;
}
} else {
if(iRead(pc, &i)){
if(v2p(pc, &pAddr, EXECUTE)){ exception(0, 12); return; }
if(iRead(pAddr, &i)){
exception(0, 1);
return;
}
@ -561,7 +615,8 @@ public:
if(address & (size-1)){
exception(0, 4, address);
} else {
if(dRead(address, size, &data)){
if(v2p(address, &pAddr, READ)){ exception(0, 13); return; }
if(dRead(pAddr, size, &data)){
exception(0, 5, address);
} else {
switch ((i >> 12) & 0x7) {
@ -580,7 +635,8 @@ public:
if(address & (size-1)){
exception(0, 6, address);
} else {
dWrite(address, size, i32_rs2);
if(v2p(address, &pAddr, WRITE)){ exception(0, 15); return; }
dWrite(pAddr, size, i32_rs2);
pcWrite(pc + 4);
}
}break;
@ -645,18 +701,18 @@ public:
switch(i){
case 0x30200073:{ //MRET
if(privilege < 3){ ilegalInstruction(); return;}
status.mpp = 0;
privilege = status.mpp;
status.mie = status.mpie;
status.mpie = 1;
privilege = status.mpp;
status.mpp = 0;
pcWrite(mepc);
}break;
case 0x10200073:{ //SRET
if(privilege < 1){ ilegalInstruction(); return;}
status.spp = 0;
privilege = status.spp;
status.sie = status.spie;
status.spie = 1;
privilege = status.spp;
status.spp = 0;
pcWrite(sepc);
}break;
case 0x00000073:{ //ECALL
@ -699,7 +755,8 @@ public:
if(address & 0x3){
exception(0, 4, address);
} else {
if(dRead(i16_rf1 + i16_lw_imm, 4, &data)) {
if(v2p(address, &pAddr, READ)){ exception(0, 13); return; }
if(dRead(address, 4, &data)) {
exception(1, 5, address);
} else {
rfWrite(i16_addr2, data); pcWrite(pc + 2);
@ -711,7 +768,8 @@ public:
if(address & 0x3){
exception(0, 6, address);
} else {
dWrite(address, 4, i16_rf2);
if(v2p(address, &pAddr, WRITE)){ exception(0, 15); return; }
dWrite(pAddr, 4, i16_rf2);
pcWrite(pc + 2);
}
}break;
@ -746,7 +804,8 @@ public:
if(address & 0x3){
exception(0, 4, address);
} else {
if(dRead(address, 4, &data)){
if(v2p(address, &pAddr, READ)){ exception(0, 13); return; }
if(dRead(pAddr, 4, &data)){
exception(1, 5, address);
} else {
rfWrite(rd32, data); pcWrite(pc + 2);
@ -775,7 +834,8 @@ public:
if(address & 3){
exception(0,6, address);
} else {
dWrite(address, 4, regs[iBits(2,5)]); pcWrite(pc + 2);
if(v2p(address, &pAddr, WRITE)){ exception(0, 15); return; }
dWrite(pAddr, 4, regs[iBits(2,5)]); pcWrite(pc + 2);
}
}break;
}
@ -884,7 +944,8 @@ public:
cout << "dRead size=" << size << endl;
fail();
}
if(address & (size-1) != 0) cout << "Ref did a unaligned read" << endl;
if(address & (size-1) != 0)
cout << "Ref did a unaligned read" << endl;
if((address & 0xF0000000) == 0xF0000000){
MemRead t = periphRead.front();
if(t.address != address || t.size != size){
@ -899,7 +960,8 @@ public:
return false;
}
virtual void dWrite(int32_t address, int32_t size, uint32_t data){
if(address & (size-1) != 0) cout << "Ref did a unaligned write" << endl;
if(address & (size-1) != 0)
cout << "Ref did a unaligned write" << endl;
if((address & 0xF0000000) == 0xF0000000){
MemWrite w;
w.address = address;
@ -2879,6 +2941,10 @@ int main(int argc, char **argv, char **env) {
printf("BOOT\n");
timespec startedAt = timer_start();
#ifdef MMU
redo(REDO,Workspace("mmu").withRiscvRef()->loadHex("../raw/mmu/build/mmu.hex")->bootAt(0x80000000u)->run(50e3););
#endif
return 0;
for(int idx = 0;idx < 1;idx++){

View File

@ -1,4 +1,4 @@
DEBUG?=no
DEBUG?=yes
IBUS?=CACHED
IBUS_TC?=no