| //Original:/proj/frio/dv/testcases/lmu/lmu_excpt_prot1/lmu_excpt_prot1.dsp |
| // Description: LMU protection exceptions |
| # mach: bfin |
| # sim: --environment operating |
| |
| #include "test.h" |
| .include "testutils.inc" |
| start |
| |
| include(selfcheck.inc) |
| include(std.inc) |
| include(mmrs.inc) |
| |
| //------------------------------------- |
| |
| // Test LMU/CPLB exceptions |
| |
| // Basic outline: |
| // Set exception handler |
| // program CPLB Entries |
| // Enable CPLB in DMEM_CNTL |
| // perform access |
| // verify exception occurred |
| |
| CHECK_INIT(p5, 0xEFFFFFFC); |
| |
| A0 = 0; |
| |
| //------------------------- |
| // Zero the CPLB Address and Data regs. |
| |
| LD32(p0, DCPLB_ADDR0); |
| R0 = 0; |
| [ P0 ++ ] = R0; // 0 |
| [ P0 ++ ] = R0; // 1 |
| [ P0 ++ ] = R0; // 2 |
| [ P0 ++ ] = R0; // 3 |
| [ P0 ++ ] = R0; // 4 |
| [ P0 ++ ] = R0; // 5 |
| [ P0 ++ ] = R0; // 6 |
| [ P0 ++ ] = R0; // 7 |
| [ P0 ++ ] = R0; // 8 |
| [ P0 ++ ] = R0; // 9 |
| [ P0 ++ ] = R0; // 10 |
| [ P0 ++ ] = R0; // 11 |
| [ P0 ++ ] = R0; // 12 |
| [ P0 ++ ] = R0; // 13 |
| [ P0 ++ ] = R0; // 14 |
| [ P0 ++ ] = R0; // 15 |
| |
| LD32(p0, DCPLB_DATA0); |
| [ P0 ++ ] = R0; // 0 |
| [ P0 ++ ] = R0; // 1 |
| [ P0 ++ ] = R0; // 2 |
| [ P0 ++ ] = R0; // 3 |
| [ P0 ++ ] = R0; // 4 |
| [ P0 ++ ] = R0; // 5 |
| [ P0 ++ ] = R0; // 6 |
| [ P0 ++ ] = R0; // 7 |
| [ P0 ++ ] = R0; // 8 |
| [ P0 ++ ] = R0; // 9 |
| [ P0 ++ ] = R0; // 10 |
| [ P0 ++ ] = R0; // 11 |
| [ P0 ++ ] = R0; // 12 |
| [ P0 ++ ] = R0; // 13 |
| [ P0 ++ ] = R0; // 14 |
| [ P0 ++ ] = R0; // 15 |
| |
| // Now set the CPLB entries we will need |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| // Data area for the desired error |
| WR_MMR(DCPLB_ADDR0, 0x800, p0, r0); |
| WR_MMR(DCPLB_ADDR1, 0x1000, p0, r0); |
| WR_MMR(DCPLB_DATA0, PAGE_SIZE_1K|CPLB_VALID|CPLB_DIRTY|CPLB_L1_CACHABLE, p0, r0); |
| WR_MMR(DCPLB_ADDR2, 0x2000, p0, r0); |
| WR_MMR(DCPLB_ADDR3, 0x3000, p0, r0); |
| WR_MMR(DCPLB_ADDR4, 0x4000, p0, r0); |
| WR_MMR(DCPLB_ADDR5, 0x5000, p0, r0); |
| WR_MMR(DCPLB_ADDR6, 0x6000, p0, r0); |
| WR_MMR(DCPLB_ADDR7, 0x7000, p0, r0); |
| |
| // CHECKREG segment |
| WR_MMR(DCPLB_ADDR14, 0xEFFFFC00, p0, r0); |
| WR_MMR(DCPLB_DATA14, PAGE_SIZE_1K|CPLB_VALID|CPLB_DIRTY|CPLB_WT|CPLB_L1_CACHABLE|CPLB_SUPV_WR|CPLB_USER_RW, p0, r0); |
| |
| // MMR space |
| WR_MMR(DCPLB_ADDR15, 0xFFC00000, p0, r0); |
| WR_MMR(DCPLB_DATA15, PAGE_SIZE_4M|CPLB_VALID|CPLB_DIRTY|CPLB_SUPV_WR, p0, r0); |
| |
| // setup interrupt controller with exception handler address |
| WR_MMR_LABEL(EVT3, handler, p0, r1); |
| WR_MMR_LABEL(EVT15, int_15, p0, r1); |
| WR_MMR(EVT_IMASK, 0xFFFFFFFF, p0, r0); |
| WR_MMR(EVT_OVERRIDE, 0x00000000, p0, r0); |
| |
| // enable CPLB |
| WR_MMR(DMEM_CONTROL, ENDM | ENDCPLB | DMC_AB_CACHE, p0, r0); |
| NOP;NOP;NOP;NOP;NOP; // in lieu of CSYNC |
| |
| // Address for slot 0 accesses |
| // LD32(p4, 0xEFFFFFF8); |
| |
| // go to user mode. and enable exceptions |
| LD32_LABEL(r0, User); |
| RETI = R0; |
| |
| // But first raise interrupt 15 so we can do one test |
| // in supervisor mode. |
| RAISE 15; |
| NOP; |
| |
| RTI; |
| |
| // Nops to work around ICache bug |
| NOP;NOP;NOP;NOP;NOP; |
| NOP;NOP;NOP;NOP;NOP; |
| |
| |
| int_15: |
| // Interrupt 15 handler - needed to try supervisor access with exceptions enabled |
| //------------------------------------------------------- |
| // Protection violation - Illegal Supervisor Write Access |
| R0 = 0;R1 = 0;R2 = 0;R3 = 0;R4 = 0;R5 = 0;R6 = 0;R7 = 0; |
| |
| LD32(i1, 0x800); |
| LD32(r1, 0xDEADBEEF); |
| |
| LD32(p2, DCPLB_DATA0); |
| LD32(r2, PAGE_SIZE_1K|CPLB_VALID|CPLB_DIRTY|CPLB_L1_CACHABLE|CPLB_SUPV_WR); |
| |
| LD32(p3, DCPLB_DATA1); |
| LD32(r3, PAGE_SIZE_1K|CPLB_VALID|CPLB_DIRTY|CPLB_L1_CACHABLE|CPLB_SUPV_WR); |
| |
| |
| X0: //[p1] = r1; // Exception should occur here |
| A0 = 0 || NOP || [ I1 ] = R1; // test access with DAG1 |
| |
| |
| // Now check that handler read correct values |
| CHECKREG(r4,0x23); // supv and EXCPT_PROT |
| CHECKREG(r5, 0x800); |
| CHECKREG(r6, (FAULT_SUPV|FAULT_WRITE|FAULT_DAG1 | FAULT_CPLB0)); |
| CHECKREG_SYM(r7, X0, r0); // RETX should be value of X0 (HARDCODED ADDR!!) |
| |
| // go to user mode. and enable exceptions |
| LD32_LABEL(r0, User); |
| RTI; |
| NOP;NOP;NOP;NOP;NOP; |
| NOP;NOP;NOP;NOP;NOP; |
| |
| |
| User: |
| NOP;NOP;NOP;NOP;NOP; |
| |
| //------------------------------------------------------- |
| // Protection violation - Illegal User Write Access |
| R0 = 0;R1 = 0;R2 = 0;R3 = 0;R4 = 0;R5 = 0;R6 = 0;R7 = 0; |
| |
| LD32(i1, 0x1000); |
| LD32(r1, 0xDEADBEEF); |
| |
| |
| // values to fix up current test |
| LD32(p2, DCPLB_DATA1); |
| LD32(r2, PAGE_SIZE_1K|CPLB_VALID|CPLB_DIRTY|CPLB_L1_CACHABLE|CPLB_USER_RW|CPLB_SUPV_WR); |
| |
| // values for next test |
| LD32(p3, DCPLB_DATA2); |
| LD32(r3, PAGE_SIZE_1K|CPLB_VALID|CPLB_DIRTY|CPLB_L1_CACHABLE); |
| |
| X1: //[p1] = r1; // Exception should occur here |
| A0 = 0 || NOP || [ I1 ] = R1; // test access with DAG1 |
| |
| // Now check that handler read correct values |
| |
| CHECKREG(r4,0x23); // supv and EXCPT_PROT |
| CHECKREG(r5, 0x1000); |
| CHECKREG(r6, (FAULT_USER|FAULT_WRITE|FAULT_DAG1 | FAULT_CPLB1)); |
| CHECKREG_SYM(r7, X1, r0); // RETX should be value of X1 (HARDCODED ADDR!!) |
| |
| |
| //------------------------------------------------------- |
| // Protection violation - Illegal User Read Access |
| R0 = 0;R1 = 0;R2 = 0;R3 = 0;R4 = 0;R5 = 0;R6 = 0;R7 = 0; |
| |
| LD32(i1, 0x2000); |
| LD32(r1, 0xDEADBEEF); |
| |
| LD32(p2, DCPLB_DATA2); |
| LD32(r2, PAGE_SIZE_1K|CPLB_VALID|CPLB_DIRTY|CPLB_L1_CACHABLE|CPLB_USER_RO|CPLB_SUPV_WR); |
| |
| LD32(p3, DCPLB_DATA3); |
| LD32(r3, PAGE_SIZE_1K|CPLB_VALID|CPLB_L1_CACHABLE|CPLB_USER_RW|CPLB_SUPV_WR); |
| |
| X2: //[p1] = r1; // Exception should occur here |
| A0 = 0 || NOP || R0 = [ I1 ]; // test access with DAG1 |
| |
| |
| // Now check that handler read correct values |
| CHECKREG(r4,0x23); // supv and EXCPT_PROT |
| CHECKREG(r5, 0x2000); |
| CHECKREG(r6, (FAULT_USER|FAULT_READ|FAULT_DAG1 | FAULT_CPLB2)); |
| CHECKREG_SYM(r7, X2, r0); // RETX should be value of X2 (HARDCODED ADDR!!) |
| |
| //------------------------------------------------------- |
| // Protection violation - Illegal Dirty Page Access |
| R0 = 0;R1 = 0;R2 = 0;R3 = 0;R4 = 0;R5 = 0;R6 = 0;R7 = 0; |
| |
| LD32(i1, 0x3000); |
| LD32(r1, 0xDEADBEEF); |
| |
| LD32(p2, DCPLB_DATA3); |
| LD32(r2, PAGE_SIZE_1K|CPLB_VALID|CPLB_DIRTY|CPLB_L1_CACHABLE|CPLB_USER_RW|CPLB_SUPV_WR); |
| |
| LD32(p3, DCPLB_DATA4); |
| LD32(r3, PAGE_SIZE_1K|CPLB_VALID|CPLB_DA0ACC|CPLB_DIRTY|CPLB_L1_CACHABLE|CPLB_SUPV_WR); |
| |
| |
| X3: //[p1] = r1; // Exception should occur here |
| A0 = 0 || NOP || [ I1 ] = R1; // test access with DAG1 |
| |
| |
| // Now check that handler read correct values |
| CHECKREG(r4,0x23); // supv and EXCPT_PROT |
| CHECKREG(r5, 0x3000); |
| CHECKREG(r6, (FAULT_USER|FAULT_WRITE|FAULT_DAG1 | FAULT_CPLB3)); |
| CHECKREG_SYM(r7, X3, r0); // RETX should be value of X3 (HARDCODED ADDR!!) |
| |
| //------------------------------------------------------- |
| // Protection violation - Illegal DAG1 Access |
| R0 = 0;R1 = 0;R2 = 0;R3 = 0;R4 = 0;R5 = 0;R6 = 0;R7 = 0; |
| |
| LD32(i1, 0x4000); |
| LD32(r1, 0xDEADBEEF); |
| |
| LD32(p2, DCPLB_DATA4); |
| LD32(r2, PAGE_SIZE_1K|CPLB_VALID|CPLB_DIRTY|CPLB_L1_CACHABLE|CPLB_USER_RW|CPLB_SUPV_WR); |
| |
| LD32(p3, DCPLB_DATA5); |
| LD32(r3, PAGE_SIZE_1K|CPLB_VALID|CPLB_DIRTY|CPLB_L1_CACHABLE|CPLB_USER_RW|CPLB_SUPV_WR); |
| |
| |
| X4: //[p1] = r1; // Exception should occur here |
| A0 = 0 || NOP || [ I1 ] = R1; // test access with DAG1 |
| |
| |
| // Now check that handler read correct values |
| CHECKREG(r4,0x23); // supv and EXCPT_PROT |
| CHECKREG(r5, 0x4000); |
| CHECKREG(r6, (FAULT_USER|FAULT_WRITE|FAULT_DAG1 | FAULT_CPLB4)); |
| CHECKREG_SYM(r7, X4, r0); // RETX should be value of X4 (HARDCODED ADDR!!) |
| |
| //------------------------------------------------------- |
| // L1Miss not implemented yet - skip for now.... |
| |
| // //------------------------------------------------------- |
| // // Protection violation - L1 Miss |
| // r0=0;r1=0;r2=0;r3=0;r4=0;r5=0;r6=0;r7=0; |
| // |
| // LD32(p1, 0x6000); |
| // LD32(r1, 0xDEADBEEF); |
| // |
| // LD32(p2, DCPLB_DATA6); |
| // LD32(r2, PAGE_SIZE_1K|CPLB_VALID|CPLB_DIRTY|CPLB_L1_CACHABLE|CPLB_USER_RW|CPLB_SUPV_WR); |
| // |
| // LD32(p3, DCPLB_DATA7); |
| // LD32(r3, PAGE_SIZE_1K|CPLB_VALID|CPLB_DIRTY|CPLB_USER_RW|CPLB_SUPV_WR); |
| // |
| // |
| //X6: //[p1] = r1; // Exception should occur here |
| // r0 = [p1]; |
| // |
| // |
| // // Now check that handler read correct values |
| // CHECKREG(r4,0x23); // supv and EXCPT_PROT |
| // CHECKREG(r5, 0x6000); |
| // // CHECKREG(r6, FAULT_USER|FAULT_WRITE|FAULT_DAG1 | FAULT_CPLB6); |
| // CHECKREG_SYM(r7, X6, r0); // RETX should be value of X6 (HARDCODED ADDR!!) |
| |
| |
| //------------------------------------------------------- |
| dbg_pass; |
| |
| |
| handler: |
| // generic protection exception handler |
| // Inputs: |
| // p2: addr of CPLB entry to be modified ( current test) |
| // r2: new data for CPLB entry |
| // |
| // p3: addr of CPLB entry to be modified ( next test) |
| // r3: new data for CPLB entry |
| // |
| // Outputs: |
| // r4: SEQSTAT |
| // r5: DCPLB_FAULT_ADDR |
| // r6: DCPLB_STATUS |
| // r7: RETX (instruction addr where exception occurred) |
| |
| |
| R4 = SEQSTAT; // Get exception cause |
| |
| // read data addr which caused exception |
| RD_MMR(DCPLB_FAULT_ADDR, p0, r5); |
| RD_MMR(DCPLB_STATUS, p0, r6); |
| |
| // Reset status regs |
| WR_MMR(DCPLB_FAULT_ADDR, 0, p0, r0); |
| WR_MMR(DCPLB_STATUS, 0, p0, r0); |
| |
| R7 = RETX; // get address of excepting instruction |
| |
| |
| // modify CPLB to allow access. Main pgm passes in addr and data |
| [ P2 ] = R2; |
| |
| // Set up for next test |
| [ P3 ] = R3; |
| |
| NOP;NOP;NOP;NOP;NOP;NOP;NOP; // in lieu of CSYNC; |
| |
| // return from exception and re-execute offending instruction |
| RTX; |
| |
| // Nops to work around ICache bug |
| NOP;NOP;NOP;NOP;NOP; |
| NOP;NOP;NOP;NOP;NOP; |
| |
| |
| .section MEM_0x800,"aw" |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |
| |
| .section MEM_0x1000,"aw" |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |
| |
| .section MEM_0x2000,"aw" |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |
| |
| .section MEM_0x3000,"aw" |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |
| |
| .section MEM_0x4000,"aw" |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |
| |
| .section MEM_0x5000,"aw" |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |
| |
| // Need a cache miss to test CPLB_L1REF |
| //.data 0x6000 |
| // .dd 0x00000000 |
| // .dd 0x00000000 |
| // .dd 0x00000000 |
| // .dd 0x00000000 |
| |
| .section MEM_0x7000,"aw" |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |
| .dd 0x00000000 |