109 lines
2.8 KiB
ArmAsm
109 lines
2.8 KiB
ArmAsm
/*
|
|
* 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
|