/* This code reads random values from memory and adds or subtracts one * depending on the sign of the read value. With branch folding enabled, it * takes the wrong branch about once every million times. * * To run the test, compile and link it like this: * avr32-gcc -nostdlib -mcpu=ap7000 wrong-branch-test-standalone-interrupts.S -o wrong-branch-test-standalone-interrupts.elf */ #include #include #define PLL_MUL 7 #define PLL_DIV 1 #define COUNT_INCREASE 100000 #define LOOP_ALGO 1 .global _start _start: mov r0, 0 cache r0[4], 8 cache r0[0], 0 sync 0 mov sp, lo(AVR32_SRAM1_ADDRESS + AVR32_SRAM1_SIZE) orh sp, hi(AVR32_SRAM1_ADDRESS + AVR32_SRAM1_SIZE) rcall main 1: breakpoint rjmp 1b .balign(0x1000) _evba: rjmp unknown_exception /* Unrecoverable exception */ nop rjmp unknown_exception /* TLB multiple hit */ nop rjmp unknown_exception /* Bus error data fetch */ nop rjmp unknown_exception /* Bus error instruction fetch */ nop rjmp unknown_exception /* NMI */ nop rjmp unknown_exception /* Instruction address */ nop rjmp unknown_exception /* ITLB miss */ nop rjmp unknown_exception /* ITLB protection */ nop rjmp unknown_exception /* Breakpoint */ nop rjmp unknown_exception /* Illegal opcode */ nop rjmp unknown_exception /* Unimplemented instruction */ nop rjmp unknown_exception /* Privilege violation */ nop rjmp unknown_exception /* Floating-point */ nop rjmp unknown_exception /* Coprocessor absent */ nop rjmp unknown_exception /* Supervisor call */ nop rjmp unknown_exception /* Data address (read) */ nop rjmp unknown_exception /* Data address (write) */ nop rjmp unknown_exception /* DTLB miss (read) */ nop rjmp unknown_exception /* DTLB miss (write) */ nop rjmp unknown_exception /* DTLB protection (read) */ nop rjmp unknown_exception /* DTLB protection (write) */ nop rjmp unknown_exception /* DTLB modified */ nop .size _evba, . - _evba .align(2) .type int0_handler, %function .func int0_handler int0_handler: /* Increment COMPARE with COUNT_INCREASE variable * r11 holds the COMPARE value set last time (and during init) * r12 holds COUNT_INCREASE value */ add r11, r12 subeq r11, -1 mtsr AVR32_COMPARE, r11 rete .endfunc .align(2) .type unknown_exception, %function .func unknown_exception unknown_exception: rete .endfunc .align(2) .type main, %function .func main main: setup_smc_cs0_timing: /* Setup SMC CS0 timings */ mov r6, lo(AVR32_SMC_ADDRESS) orh r6, hi(AVR32_SMC_ADDRESS) mov r9, lo(0x00031103) orh r9, hi(0x00031103) st.w r6[AVR32_SMC_MODE0], r9 mov r9, lo(0x000c000d) orh r9, hi(0x000c000d) st.w r6[AVR32_SMC_CYCLE0], r9 mov r9, lo(0x0b0a0906) orh r9, hi(0x0b0a0906) st.w r6[AVR32_SMC_PULSE0], r9 mov r9, lo(0x00010002) orh r9, hi(0x00010002) st.w r6[AVR32_SMC_SETUP0], r9 setup_pll_and_lock: /* Setup PLL to run at 8 x 20 MHz crystal */ mov r6, lo(AVR32_PM_ADDRESS) orh r6, hi(AVR32_PM_ADDRESS) mov r9, lo((16 << AVR32_PM_PLLCOUNT_OFFSET) \ | (PLL_MUL << AVR32_PM_PLLMUL_OFFSET) \ | (PLL_DIV << AVR32_PM_PLLDIV_OFFSET) \ | (0x4 << AVR32_PM_PLLOPT_OFFSET) \ | AVR32_PM_PLLEN_MASK) orh r9, hi((16 << AVR32_PM_PLLCOUNT_OFFSET) \ | (PLL_MUL << AVR32_PM_PLLMUL_OFFSET) \ | (PLL_DIV << AVR32_PM_PLLDIV_OFFSET) \ | (0x4 << AVR32_PM_PLLOPT_OFFSET) \ | AVR32_PM_PLLEN_MASK) st.w r6[AVR32_PM_PLL0], r9 mov r10, AVR32_PM_LOCK0_MASK wait_pll_lock: ld.w r9, r6[AVR32_PM_ISR] bld r9, AVR32_PM_LOCK0 brne wait_pll_lock setup_cpu_hsb_pbx_dividers: /* Bus speeds: CPU HSB/2 PBA/4 PBB/2 */ mov r9, lo(AVR32_PM_PBBDIV_MASK \ | AVR32_PM_PBADIV_MASK \ | (1 << AVR32_PM_PBASEL_OFFSET) \ | AVR32_PM_HSBDIV_MASK) orh r9, hi(AVR32_PM_PBBDIV_MASK \ | AVR32_PM_PBADIV_MASK \ | (1 << AVR32_PM_PBASEL_OFFSET) \ | AVR32_PM_HSBDIV_MASK) st.w r6[AVR32_PM_CKSEL], r9 switch_to_pll0: mov r9, AVR32_PM_PLLSEL_MASK st.w r6[AVR32_PM_MCCTRL], r9 setup_evba: mov r9, lo(_evba) orh r9, hi(_evba) mtsr AVR32_EVBA, r9 setup_intc_int0: /* Setup autovector for interrupt 0 at level 0 */ mov r6, lo(AVR32_INTC_ADDRESS) orh r6, hi(AVR32_INTC_ADDRESS) mov r9, int0_handler - _evba st.w r6[AVR32_INTC_IPR * 0], r9 setup_gpio_leds: /* Setup GPIO to control LEDs on PA16 (SYS) and PA19 (A) */ mov r9, 0xff mov r6, lo(AVR32_PIOB_ADDRESS) orh r6, hi(AVR32_PIOB_ADDRESS) st.w r6[AVR32_PIO_PER], r9 st.w r6[AVR32_PIO_OER], r9 st.w r6[AVR32_PIO_OWER], r9 mov r9, 1 st.w r6[AVR32_PIO_ODSR], r9 /* Set COUNT-COMPARE on fire and enable global interrupts */ set_count_compare: mov r11, 0 mov r12, lo(COUNT_INCREASE) orh r12, hi(COUNT_INCREASE) mtsr AVR32_COUNT, r11 add r11, r12 mtsr AVR32_COMPARE, r11 enable_interrupts: csrf AVR32_SR_GM_OFFSET #if 0 /* enable to turn off branch folding */ mfsr r0, 12 cbr r0, 2 mtsr 12, r0 #endif /* Algorithm triggering branch folding issue */ branch_folding_issue_algorithm: lda.w r0, random lda.w r4, ref mov r1, 0 mov r5, 0 rjmp 2f 4: mul r8, r1, r2 sub r2, 1 3: ld.sh r7, r4[r1<<1] cp.w r2, r7 brne 6f sub r5, -1 5: sub r1, -1 bfextu r1, r1, 0, 5 2: ld.sh r2, r0[r1<<1] cp.w r2, 0 /* XXX: changed from mul to div to get more cycles to get an interrupt */ divs r8, r1, r2 /* XXX: this one happens to fail, probably due to context switching * and branch folding */ brle 4b sub r2, -1 rjmp 3b 6: sub r8, r2, r7 /* r1 = index * r7 = expected result * r2 = actual result * r8 = error * r5 = iterations since last error */ /* Halt algorithm and toggle LED A, read the registers */ toggle_led: ssrf AVR32_SR_GM_OFFSET ld.w r9, r6[AVR32_PIO_ODSR] sub r9, -1 st.w r6[AVR32_PIO_ODSR], r9 mov r10, 0xffff orh r10, 2 delay_loop: sub r10, 1 brne delay_loop #if LOOP_ALGO == 0 rjmp toggle_led #else /* Optional reset r5 and jump back to algorithm */ mov r5, 0 csrf AVR32_SR_GM_OFFSET rjmp 5b #endif .endfunc .align(2) .type random, %object random: .short 0x803b, 0x15ae, 0x8f2f, 0x2ddf, 0x2226, 0xb7f1, 0x74dc, 0xe3f6 .short 0x3ce2, 0xa894, 0x322a, 0x221d, 0x8329, 0x8fb3, 0xd73e, 0x927a .short 0x68b0, 0xff8b, 0x483c, 0xac79, 0x4f93, 0xa498, 0x6ba7, 0xdf04 .short 0x0803, 0xda61, 0xa954, 0xcd49, 0xe059, 0x01f8, 0xae51, 0xff68 .size random, . - random .type ref, %object ref: .short 0x803a, 0x15af, 0x8f2e, 0x2de0, 0x2227, 0xb7f0, 0x74dd, 0xe3f5 .short 0x3ce3, 0xa893, 0x322b, 0x221e, 0x8328, 0x8fb2, 0xd73d, 0x9279 .short 0x68b1, 0xff8a, 0x483d, 0xac78, 0x4f94, 0xa497, 0x6ba8, 0xdf03 .short 0x0804, 0xda60, 0xa953, 0xcd48, 0xe058, 0x01f9, 0xae50, 0xff67 .size ref, . - ref