/* * This file is part of GreatFET * * Specialized SGPIO interrupt handler for Rhododendron. */ // Constants that point to registers we'll need to modify in the SGPIO block. .equ SGPIO_REGISTER_BLOCK_BASE, 0x40101000 .equ SGPIO_SHADOW_REGISTERS_BASE, 0x40101100 .equ SGPIO_EXCHANGE_INTERRUPT_CLEAR_REG, 0x40101F30 .equ SGPIO_EXCHANGE_INTERRUPT_STATUS_REG, 0x40101F2C .equ SGPIO_GPIO_INPUT, 0x40101210 // Buffer that we're funneling data to/from. .equ TARGET_DATA_BUFFER, 0x20008000 .equ TARGET_BUFFER_POSITION, 0x20007000 .equ TARGET_BUFFER_TX, 0x20007004 .equ TARGET_BUFFER_MASK, 0x7fff .global main .thumb_func main: // Spin until we're ready to handle an SGPIO packet: // Grab the exchange interrupt staus... ldr r0, =SGPIO_EXCHANGE_INTERRUPT_STATUS_REG ldr r0, [r0] // ... check to see if it has any interrupt bits set... lsr r0, #1 // ... and if not, jump back to the beginning. bcc main // Clear the interrupt pending bits for the SGPIO slices we're working with. ldr r0, =SGPIO_EXCHANGE_INTERRUPT_CLEAR_REG ldr r1, =0xffff str r1, [r0] // Grab the base address of the SGPIO shadow registers... ldr r7, =SGPIO_SHADOW_REGISTERS_BASE // ... and grab the address of the buffer segment we want to write to / read from. ldr r0, =TARGET_DATA_BUFFER // r0 = &buffer ldr r3, =TARGET_BUFFER_POSITION // r3 = &position_in_buffer ldr r2, [r3] // r2 = position_in_buffer add r6, r0, r2 // r6 = buffer_target = &buffer + position_in_buffer mov r8, r3 // Store &position_in_buffer. // Our slice chain is set up as follows (ascending data age; arrows are reversed for flow): // L -> F -> K -> C -> J -> E -> I -> A // Which has equivalent shadow register offsets: // 44 -> 20 -> 40 -> 8 -> 36 -> 16 -> 32 -> 0 // Load direction (TX or RX) ldr r0, =TARGET_BUFFER_TX ldr r0, [r0] // TX? lsr r0, #1 bcc direction_rx direction_tx: ldm r6!, {r0-r5} str r0, [r7, #44] str r1, [r7, #20] str r2, [r7, #40] str r3, [r7, #8 ] str r4, [r7, #36] str r5, [r7, #16] ldm r6!, {r0-r1} str r0, [r7, #32] str r1, [r7, #0] b done direction_rx: // 8 cycles ldr r0, [r7, #44] // 2 ldr r1, [r7, #20] // 2 ldr r2, [r7, #40] // 2 ldr r3, [r7, #8 ] // 2 ldr r4, [r7, #36] // 2 ldr r5, [r7, #16] // 2 stm r6!, {r0-r5} // 7 // 6 cycles ldr r0, [r7, #32] // 2 ldr r1, [r7, #0] // 2 stm r6!, {r0-r1} done: // Finally, update the buffer location... ldr r0, =TARGET_BUFFER_MASK and r0, r6, r0 // r0 = (position_in_buffer + size_copied) % buffer_size // ... restore &position_in_buffer, and store the new position there... mov r1, r8 str r0, [r1] // position_in_buffer = (position_in_buffer + size_copied) % buffer_size b main