diff --git a/firmware/crt0.S b/firmware/crt0.S index 061ffebeab..e7210e6d78 100644 --- a/firmware/crt0.S +++ b/firmware/crt0.S @@ -285,6 +285,12 @@ boot_table: /* Set up stack for FIQ mode */ msr cpsr_c, #0xd1 ldr sp, =fiq_stack +#if CONFIG_CPU == PP5020 || CONFIG_CPU == PP5002 + /* We'll load the banked FIQ mode registers with useful values here. + These values will be used in the FIQ handler in pcm_playback.c */ + ldr r12, =0x70002800 /* IISCONFIG */ + ldr r11, =p +#endif /* Let abort mode use IRQ stack */ msr cpsr_c, #0xd7 ldr sp, =irq_stack diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index 6d60c40fdb..75b3de4f90 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c @@ -330,6 +330,8 @@ static bool pcm_playing; static bool pcm_paused; static int pcm_freq = 0x6; /* 44.1 is default */ +/* NOTE: The order of these two variables is important if you use the iPod + assembler optimised fiq handler, so don't change it. */ unsigned short* p IBSS_ATTR; long p_size IBSS_ATTR; @@ -552,36 +554,38 @@ bool pcm_is_playing(void) void fiq(void) ICODE_ATTR __attribute__((naked)); void fiq(void) { + /* r12 contains IISCONFIG address (set in crt0.S to minimise code in actual + * FIQ handler. r11 contains address of p (also set in crt0.S). Most other + * addresses we need are generated by using offsets with these two. + * r12 + 0x40 is IISFIFO_WR, and r12 + 0x0c is IISFIFO_CFG. + * r8 and r9 contains local copies of p_size and p respectively. + * r10 is a working register. + */ asm volatile ( - "ldr r12, =0x70002800 \n\t" /* r12 = IISCONFIG */ - "ldr r11, [r12] \n\t" - "bic r11, r11, #0x2 \n\t" /* clear interrupt */ - "str r11, [r12] \n\t" - "ldr r8, =p_size \n\t" - "ldr r9, =p \n\t" - "ldr r8, [r8] \n\t" /* r8 = p_size */ - "ldr r9, [r9] \n\t" /* r9 = p */ - "ldr r10, =0x70002840 \n\t" /* r10 = IISFIFO_WR */ - "ldr r11, =0x7000280c \n\t" /* r11 = IISFIFO_CFG */ + "ldr r10, [r12] \n\t" + "bic r10, r10, #0x2 \n\t" /* clear interrupt */ + "str r10, [r12] \n\t" + "ldr r8, [r11, #4] \n\t" /* r8 = p_size */ + "ldr r9, [r11] \n\t" /* r9 = p */ ".loop: \n\t" "cmp r8, #0 \n\t" /* is p_size 0? */ "beq .more_data \n\t" /* if so, ask pcmbuf for more data */ ".fifo_loop: \n\t" - "ldr r12, [r11] \n\t" /* read IISFIFO_CFG to check FIFO status */ - "and r12, r12, #0x3f0000\n\t" - "cmp r12, #0x10000 \n\t" + "ldr r10, [r12, #0x0c]\n\t" /* read IISFIFO_CFG to check FIFO status */ + "and r10, r10, #0x3f0000\n\t" + "cmp r10, #0x10000 \n\t" "bls .fifo_full \n\t" /* FIFO full, exit */ - "ldr r12, [r9], #4 \n\t" /* load two samples to r12 */ - "mov r12, r12, ror #16\n\t" /* put left sample at the top bits */ - "str r12, [r10] \n\t" /* write top sample, lower sample ignored */ - "mov r12, r12, lsl #16\n\t" /* shift lower sample up */ - "str r12, [r10] \n\t" /* then write it */ + "ldr r10, [r9], #4 \n\t" /* load two samples */ + "mov r10, r10, ror #16\n\t" /* put left sample at the top bits */ + "str r10, [r12, #0x40]\n\t" /* write top sample, lower sample ignored */ + "mov r10, r10, lsl #16\n\t" /* shift lower sample up */ + "str r10, [r12, #0x40]\n\t" /* then write it */ "subs r8, r8, #4 \n\t" /* check if we have more samples */ "bne .fifo_loop \n\t" /* yes, continue */ ".more_data: \n\t" - "stmdb sp!, { r0-r3, lr}\n\t" /* stack scratch regs and lr */ - "ldr r0, =p \n\t" /* load parameters to callback_for_more */ - "ldr r1, =p_size \n\t" + "stmdb sp!, { r0-r3, r12, lr}\n\t" /* stack scratch regs and lr */ + "mov r0, r11 \n\t" /* r0 = &p */ + "add r1, r11, #4 \n\t" /* r1 = &p_size */ "str r9, [r0] \n\t" /* save internal copies of variables back */ "str r8, [r1] \n\t" "ldr r2, =callback_for_more\n\t" @@ -589,36 +593,30 @@ void fiq(void) "cmp r2, #0 \n\t" /* check for null pointer */ "movne lr, pc \n\t" /* call callback_for_more */ "bxne r2 \n\t" - "ldmia sp!, { r0-r3, lr}\n\t" - "ldr r8, =p_size \n\t" /* reload p_size and p */ - "ldr r9, =p \n\t" - "ldr r8, [r8] \n\t" - "ldr r9, [r9] \n\t" + "ldmia sp!, { r0-r3, r12, lr}\n\t" + "ldr r8, [r11, #4] \n\t" /* reload p_size and p */ + "ldr r9, [r11] \n\t" "cmp r8, #0 \n\t" /* did we actually get more data? */ "bne .loop \n\t" /* yes, continue to try feeding FIFO */ ".dma_stop: \n\t" /* no more data, do dma_stop() and exit */ "ldr r10, =pcm_playing\n\t" "strb r8, [r10] \n\t" /* pcm_playing = false (r8=0, look above) */ - "ldr r10, =0x70002800 \n\t" /* r10 = IISCONFIG */ - "ldr r11, [r10] \n\t" - "bic r11, r11, #0x20000002\n\t" /* disable playback FIFO and IRQ */ - "str r11, [r10] \n\t" + "ldr r10, [r12] \n\t" + "bic r10, r10, #0x20000002\n\t" /* disable playback FIFO and IRQ */ + "str r10, [r12] \n\t" "mrs r10, cpsr \n\t" "orr r10, r10, #0x40 \n\t" /* disable FIQ */ "msr cpsr_c, r10 \n\t" "ldr r10, =pcm_paused \n\t" "strb r8, [r10] \n\t" /* pcm_paused = false */ ".exit: \n\t" - "ldr r10, =p_size \n\t" /* save back p_size and p, then exit */ - "ldr r11, =p \n\t" - "str r8, [r10] \n\t" + "str r8, [r11, #4] \n\t" "str r9, [r11] \n\t" "subs pc, lr, #4 \n\t" /* FIQ specific return sequence */ ".fifo_full: \n\t" /* enable IRQ and exit */ - "ldr r12, =0x70002800 \n\t" /* r12 = IISCONFIG */ - "ldr r11, [r12] \n\t" - "orr r11, r11, #0x2 \n\t" /* set interrupt */ - "str r11, [r12] \n\t" + "ldr r10, [r12] \n\t" + "orr r10, r10, #0x2 \n\t" /* set interrupt */ + "str r10, [r12] \n\t" "b .exit \n\t" ); }