I make no promises about this, but it might work. It’s been a long time since I’ve looked at assembly…
begin and end have to be 4 byte aligned, and the end should include the necessary 0 bits (at least 49 of them)
[code].syntax unified
/* R0 is current flash memory read address
r1 is end of flash
r2 is 1
r3 is current 4 byte
r4 is next 4 byte
r5 is PB11 set bitband address
r6 is PB11 reset bitband address
r7 is PB13 data bitband address
sck starts high
*/
#define P_BASE 0x40000000
#define BBP_BASE 0x42000000
#define GPIOB_OFFSET 0x11c00
#define GPIOB_BASE P_BASE+GPIOB_OFFSET
#define GPIO_ODR_OFFSET 0x0c
#define GPIOB_ODR (GPIOB_BASE+GPIO_ODR_OFFSET)
#define GPIO_BSRR_OFFSET 0x10
#define GPIOB_BSRR (GPIOB_BASE + GPIO_BSRR_OFFSET)
#define GPIO_BRR_OFFSET 0x14
#define GPIOB_BRR (GPIOB_BASE+GPIO_BRR_OFFSET)
#define BB_GPIOB_ODR(n) (BBP_BASE + ((GPIOB_OFFSET + GPIO_ODR_OFFSET) * 32) + (n4))
#define BB_GPIOB_BSRR(n) (BBP_BASE + ((GPIOB_OFFSET + GPIO_BSRR_OFFSET) * 32) + (n4))
#define BB_GPIOB_BRR(n) (BBP_BASE + ((GPIOB_OFFSET + GPIO_BRR_OFFSET) * 32) + (n4))
/
#define LOAD_ADDR(r, addr) mov r, # (addr & 0x0000ffff)
/*; movt r, # (0x0000ffff & ((addr & 0xffff0000)>>16))
*/
#define LOAD_ADDR(r, addr) ldr r, =(addr)
#define SET_SCK_LOW str r2, [r6]
#define SET_SCK_HIGH str r2, [r5]
#define LSR_DATA lsrs r3, r3, #1
#define SET_DATA str r3, [r7]
#define DOBIT SET_SCK_LOW ; SET_DATA ; LSR_DATA ; SET_SCK_HIGH ; nop; nop
/* THUMB2 function definition
void fpga_load(void *begin_addr, void *end_addr)
*/
.section .text
.global fpga_load
.thumb_func
fpga_load:
push {r4-r7}
LOAD_ADDR(r5, BB_GPIOB_BSRR(11))
LOAD_ADDR(r6, BB_GPIOB_BRR(11))
LOAD_ADDR(r7, BB_GPIOB_ODR(13))
SET_SCK_HIGH @ should be high since reset
mov r2, #1
ldr r3, [r0] @ 4 cycles - 2 read, 2 wait state
rbit r3, r3
@ begin critical timing - 9 cycles total per bit max
loop:
DOBIT @ bit 0
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT @ bit 10
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT @ bit 20
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
DOBIT
SET_SCK_LOW @ bit 29
SET_DATA
LSR_DATA
SET_SCK_HIGH
adds r0, #4
nop
SET_SCK_LOW @ bit 30
SET_DATA
LSR_DATA
SET_SCK_HIGH
ldr r4, [r0]
SET_SCK_LOW @ bit 31
SET_DATA
cmp r0, r1
beq finished @ from cmp up above - if finished, jump and be done
SET_SCK_HIGH @ if not finished, get here - no branch = 1 cycle
rbit r3, r4
b loop
finished:
SET_SCK_HIGH
pop {r4-r7}
bx lr
constants:
[/code]