void arch_set_dtlb(void *vaddr,void *paddr) { unsigned int flags = DTLB_PR_NOLIMIT; unsigned int mr = ((unsigned int)vaddr & SPR_DTLBMR_VPN) | SPR_ITLBMR_V; unsigned int tr = ((unsigned int)paddr & SPR_DTLBTR_PPN) | (flags & DTLB_PR_MASK) | SPR_DTLBTR_A | SPR_DTLBTR_D; unsigned int set = ((((unsigned int)vaddr) >> PAGE_BITS) & 63); or1k_mtspr (SPR_DTLBMR_BASE(0)+set, mr); or1k_mtspr (SPR_DTLBTR_BASE(0)+set, tr); }
/* Data page fault exception handler */ void dpage_fault_handler (void) { unsigned long ea; int set, way = 0; int i; /* Get EA that cause the exception */ ea = mfspr (SPR_EEAR_BASE); /* Find TLB set and way */ set = (ea / PAGE_SIZE) % DTLB_SETS; for (i = 0; i < DTLB_WAYS; i++) { if ((mfspr (SPR_DTLBMR_BASE(i) + set) & SPR_DTLBMR_VPN) == (ea & SPR_DTLBMR_VPN)) { way = i; break; } } /* Give permission */ mtspr (SPR_DTLBTR_BASE(way) + set, (mfspr (SPR_DTLBTR_BASE(way) + set) & ~DTLB_PR_NOLIMIT) | dtlb_val); except_mask |= 1 << V_DPF; except_count++; }
/* DTLB miss exception handler */ void dtlb_miss_handler (void) { unsigned long ea; int set, way = 0; int i; /* Get EA that cause the exception */ ea = mfspr (SPR_EEAR_BASE); /* Find TLB set and LRU way */ set = (ea / PAGE_SIZE) % DTLB_SETS; for (i = 0; i < DTLB_WAYS; i++) { if ((mfspr (SPR_DTLBMR_BASE(i) + set) & SPR_DTLBMR_LRU) == 0) { way = i; break; } } mtspr (SPR_DTLBMR_BASE(way) + set, (ea & SPR_DTLBMR_VPN) | SPR_DTLBMR_V); mtspr (SPR_DTLBTR_BASE(way) + set, (ea & SPR_DTLBTR_PPN) | dtlb_val); except_mask |= 1 << V_DTLB_MISS; except_count++; }
/* Exception priority test */ void except_priority_test (void) { int i, j; unsigned long ea, ta, ret; /* Invalidate all entries in ITLB */ for (i = 0; i < ITLB_WAYS; i++) { for (j = 0; j < ITLB_SETS; j++) { mtspr (SPR_ITLBMR_BASE(i) + j, 0); mtspr (SPR_ITLBTR_BASE(i) + j, 0); } } /* Set one to one translation for the use of this program */ for (i = 0; i < TLB_TEXT_SET_NB; i++) { ea = RAM_START + (i*PAGE_SIZE); ta = RAM_START + (i*PAGE_SIZE); mtspr (SPR_ITLBMR_BASE(0) + i, ea | SPR_ITLBMR_V); mtspr (SPR_ITLBTR_BASE(0) + i, ta | ITLB_PR_NOLIMIT); } /* Set dtlb no permisions */ itlb_val = SPR_ITLBTR_CI; /* Invalidate all entries in DTLB */ for (i = 0; i < DTLB_WAYS; i++) { for (j = 0; j < DTLB_SETS; j++) { mtspr (SPR_DTLBMR_BASE(i) + j, 0); mtspr (SPR_DTLBTR_BASE(i) + j, 0); } } /* Set one to one translation for the use of this program */ for (i = 0; i < TLB_DATA_SET_NB; i++) { ea = RAM_START + (i*PAGE_SIZE); ta = RAM_START + (i*PAGE_SIZE); mtspr (SPR_DTLBMR_BASE(0) + i, ea | SPR_ITLBMR_V); mtspr (SPR_DTLBTR_BASE(0) + i, ta | DTLB_PR_NOLIMIT); } /* Init tick timer */ tick_init (1, 1); /* Set dtlb no permisions */ dtlb_val = SPR_DTLBTR_CI; /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; /* Enable IMMU */ immu_enable (); /* The following is currently disabled due to differing behavior between or1ksim and the OR1200 RTL. Or1ksim appears to receive only 1 exception during the call_with_int() call. The OR1200 correctly, in my opionion, reports 2 exceptions - ITLB miss and tick timer. -- Julius TODO: Investigate why or1ksim isn't reporting ITLB miss. */ #if 0 /* Check if there was INT exception */ call_with_int (RAM_START + (RAM_SIZE) + (TLB_TEXT_SET_NB*PAGE_SIZE), 0); printf("ec:%d 0x%lx\n",except_count,except_mask); ASSERT(except_count == 2); ASSERT(except_mask == ((1 << V_TICK) | (1 << V_ITLB_MISS))); printf("epc %8lx\n",except_pc); ASSERT(except_pc == (RAM_START + (RAM_SIZE) + (TLB_TEXT_SET_NB*PAGE_SIZE))); /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; #endif /* Check if there was ITLB exception */ call (RAM_START + (RAM_SIZE) + (TLB_TEXT_SET_NB*PAGE_SIZE), 0); ASSERT(except_count == 1); ASSERT(except_mask == (1 << V_ITLB_MISS)); ASSERT(except_pc == (RAM_START + (RAM_SIZE) + (TLB_TEXT_SET_NB*PAGE_SIZE))); ASSERT(except_ea == (RAM_START + (RAM_SIZE) + (TLB_TEXT_SET_NB*PAGE_SIZE))); /* Set dtlb permisions */ itlb_val |= SPR_ITLBTR_SXE; /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; /* Check if there was IPF exception */ call (RAM_START + (RAM_SIZE) + (TLB_TEXT_SET_NB*PAGE_SIZE), 0); ASSERT(except_count == 1); ASSERT(except_mask == (1 << V_IPF)); ASSERT(except_pc == (RAM_START + (RAM_SIZE) + (TLB_TEXT_SET_NB*PAGE_SIZE))); ASSERT(except_ea == (RAM_START + (RAM_SIZE) + (TLB_TEXT_SET_NB*PAGE_SIZE))); /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; /* Disable MMU */ immu_disable (); /* Set illegal instruction. JPB. Use a really illegal instruction, not l.cust8 0x3ffffff. */ REG32(RAM_START + (RAM_SIZE/2) + (TLB_TEXT_SET_NB*PAGE_SIZE) + 0) = 0x00000000; REG32(RAM_START + (RAM_SIZE/2) + (TLB_TEXT_SET_NB*PAGE_SIZE) + 4) = 0xe8000000; REG32(RAM_START + (RAM_SIZE/2) + (TLB_TEXT_SET_NB*PAGE_SIZE) + 8) = 0x00000000; /* Check if there was illegal insn exception */ call (RAM_START + (RAM_SIZE/2) + (TLB_TEXT_SET_NB*PAGE_SIZE) + 4, 0); ASSERT(except_count == 1); ASSERT(except_mask == (1 << V_ILLINSN)); ASSERT(except_pc == (RAM_START + (RAM_SIZE/2) + (TLB_TEXT_SET_NB*PAGE_SIZE) + 4)); ASSERT(except_ea == (RAM_START + (RAM_SIZE/2) + (TLB_TEXT_SET_NB*PAGE_SIZE) + 4 )); /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; /* Enable DMMU */ dmmu_enable (); /* Check if there was alignment exception on read insn */ ret = call ((unsigned long)&load_acc_32, RAM_START + (RAM_SIZE) + (TLB_DATA_SET_NB*PAGE_SIZE) + 1); ASSERT(except_count == 1); ASSERT(except_mask == (1 << V_ALIGN)); ASSERT(ret == 0x12345678); ASSERT(except_pc == ((unsigned long)(load_acc_32) + 8)); ASSERT(except_ea == (RAM_START + (RAM_SIZE) + (TLB_DATA_SET_NB*PAGE_SIZE + 1))); /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; /* Check if there was DTLB exception */ ret = call ((unsigned long)&load_acc_32, RAM_START + (RAM_SIZE) + (TLB_DATA_SET_NB*PAGE_SIZE)); ASSERT(except_count == 1); ASSERT(except_mask == (1 << V_DTLB_MISS)); ASSERT(ret == 0x12345678); ASSERT(except_pc == ((unsigned long)(load_acc_32) + 8)); ASSERT(except_ea == (RAM_START + (RAM_SIZE) + (TLB_DATA_SET_NB*PAGE_SIZE))); /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; /* Set dtlb permisions */ dtlb_val |= SPR_DTLBTR_SRE; /* Check if there was DPF exception */ ret = call ((unsigned long)&load_acc_32, RAM_START + (RAM_SIZE) + (TLB_DATA_SET_NB*PAGE_SIZE)); ASSERT(except_count == 1); ASSERT(except_mask == (1 << V_DPF)); ASSERT(ret == 0x12345678); ASSERT(except_pc == ((unsigned long)(load_acc_32) + 8)); ASSERT(except_ea == (RAM_START + (RAM_SIZE) + (TLB_DATA_SET_NB*PAGE_SIZE))); /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; /* Check if there was trap exception */ call ((unsigned long)&trap, 0); ASSERT(except_count == 1); ASSERT(except_mask == (1 << V_TRAP)); ASSERT(except_pc == (unsigned long)(trap)); }
/* Bus error test */ int buserr_test (void) { int i, j, ret; unsigned long ea, ta; /* Invalidate all entries in ITLB */ for (i = 0; i < ITLB_WAYS; i++) { for (j = 0; j < ITLB_SETS; j++) { mtspr (SPR_ITLBMR_BASE(i) + j, 0); mtspr (SPR_ITLBTR_BASE(i) + j, 0); } } /* Set one to one translation for the use of this program */ for (i = 0; i < TLB_TEXT_SET_NB; i++) { ea = RAM_START + (i*PAGE_SIZE); ta = RAM_START + (i*PAGE_SIZE); mtspr (SPR_ITLBMR_BASE(0) + i, ea | SPR_ITLBMR_V); mtspr (SPR_ITLBTR_BASE(0) + i, ta | ITLB_PR_NOLIMIT); } /* Invalidate all entries in DTLB */ for (i = 0; i < DTLB_WAYS; i++) { for (j = 0; j < DTLB_SETS; j++) { mtspr (SPR_DTLBMR_BASE(i) + j, 0); mtspr (SPR_DTLBTR_BASE(i) + j, 0); } } /* Set one to one translation for the use of this program */ for (i = 0; i < TLB_DATA_SET_NB; i++) { ea = RAM_START + (i*PAGE_SIZE); ta = RAM_START + (i*PAGE_SIZE); mtspr (SPR_DTLBMR_BASE(0) + i, ea | SPR_ITLBMR_V); mtspr (SPR_DTLBTR_BASE(0) + i, ta | DTLB_PR_NOLIMIT); } /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; /* Set IMMU translation */ ea = RAM_START + (RAM_SIZE) + ((TLB_TEXT_SET_NB)*PAGE_SIZE); itlb_val = SPR_ITLBTR_CI | SPR_ITLBTR_SXE; mtspr (SPR_ITLBMR_BASE(0) + TLB_TEXT_SET_NB, (ea & SPR_ITLBMR_VPN) | SPR_ITLBMR_V); // Set translate to invalid address: 0xee000000 mtspr (SPR_ITLBTR_BASE(0) + TLB_TEXT_SET_NB, (0xee000000 & SPR_ITLBTR_PPN) | itlb_val); /* Enable IMMU */ immu_enable (); /* Check if there was bus error exception */ ret = call (ea, 0); ASSERT(except_count == 1); ASSERT(except_mask == (1 << V_BERR)); ASSERT(except_pc == ea); ASSERT(except_ea == ea); /* Disable IMMU */ immu_disable (); /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; /* Set EA as an invalid memory location */ ea = 0xee000000; /* Check if there was bus error exception */ ret = call (ea, 0); ASSERT(except_count == 1); ASSERT(except_mask == (1 << V_BERR)); ASSERT(except_pc == ea); ASSERT(except_ea == ea); /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; /* Set DMMU translation */ ea = RAM_START + (RAM_SIZE) + ((TLB_DATA_SET_NB)*PAGE_SIZE); dtlb_val = SPR_DTLBTR_CI | SPR_DTLBTR_SRE; mtspr (SPR_DTLBMR_BASE(0) + TLB_DATA_SET_NB, (ea & SPR_DTLBMR_VPN) | SPR_DTLBMR_V); // Set translate to invalid address: 0xee000000 mtspr (SPR_DTLBTR_BASE(0) + TLB_DATA_SET_NB, (0xee000000 & SPR_DTLBTR_PPN) | dtlb_val); /* Enable DMMU */ dmmu_enable (); /* Check if there was bus error exception */ ret = call ((unsigned long)&load_acc_32, ea ); ASSERT(except_count == 1); ASSERT(except_mask == (1 << V_BERR)); ASSERT(except_pc == (unsigned long)load_acc_32 + 8); ASSERT(except_ea == ea); ASSERT(ret == 0x12345678); /* Disable DMMU */ dmmu_disable (); /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; // Set ea to invalid address ea = 0xee000000; /* Check if there was bus error exception */ ret = call ((unsigned long)&load_acc_32, ea ); ASSERT(except_count == 1); ASSERT(except_mask == (1 << V_BERR)); ASSERT(except_pc == (unsigned long)load_acc_32 + 8); ASSERT(except_ea == ea); ASSERT(ret == 0x12345678); return 0; }
/* DTLB miss test */ int dtlb_test (void) { int i, j, ret; unsigned long ea, ta; /* Invalidate all entries in DTLB */ for (i = 0; i < DTLB_WAYS; i++) { for (j = 0; j < DTLB_SETS; j++) { mtspr (SPR_DTLBMR_BASE(i) + j, 0); mtspr (SPR_DTLBTR_BASE(i) + j, 0); } } /* Set one to one translation for the use of this program */ for (i = 0; i < TLB_DATA_SET_NB; i++) { ea = RAM_START + (i*PAGE_SIZE); ta = RAM_START + (i*PAGE_SIZE); mtspr (SPR_DTLBMR_BASE(0) + i, ea | SPR_ITLBMR_V); mtspr (SPR_DTLBTR_BASE(0) + i, ta | DTLB_PR_NOLIMIT); } /* Set dtlb no permisions */ dtlb_val = SPR_DTLBTR_CI; /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; /* Set pattern */ ea = RAM_START + (RAM_SIZE/2) + ((TLB_DATA_SET_NB)*PAGE_SIZE); REG32(ea) = 0x87654321; /* Enable DMMU */ dmmu_enable (); /* Check if there was DTLB miss exception */ ret = call ((unsigned long)&load_b_acc_32, ea); ASSERT(except_count == 1); ASSERT(except_mask == (1 << V_DTLB_MISS)); ASSERT(except_pc == (unsigned long)load_b_acc_32 + 8); ASSERT(except_ea == ea); ASSERT(ret == 0x12345678); /* Set dtlb no permisions */ dtlb_val = SPR_DTLBTR_CI | SPR_DTLBTR_SRE; /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; /* Check if there was DPF miss exception */ ret = call ((unsigned long)&load_b_acc_32, ea); ASSERT(except_count == 1); ASSERT(except_mask == (1 << V_DPF)); ASSERT(except_pc == (unsigned long)load_b_acc_32 + 8); ASSERT(except_ea == ea); ASSERT(ret == 0x12345678); /* Reset except counter */ except_count = 0; except_mask = 0; except_pc = 0; except_ea = 0; ret = call ((unsigned long)&load_b_acc_32, ea); ASSERT(except_count == 0); ASSERT(ret == 0x87654321); /* Disable DMMU */ dmmu_disable (); return 0; }