Add macro versions of key parts of M0 code.

This commit is separate from the following one which uses the macros, in
order to make the diffs easier to read.
This commit is contained in:
Martin Ling
2021-12-24 13:40:00 +00:00
parent 68688e0ec4
commit 9d570cb558

View File

@ -147,6 +147,119 @@ sgpio_int .req r6
count .req r5 count .req r5
buf_ptr .req r4 buf_ptr .req r4
/* Macros */
.macro reset_counts
// Reset counts.
//
// Clobbers:
zero .req r0
mov zero, #0 // zero = 0 // 1
str zero, [state, #M0_COUNT] // state.m0_count = zero // 2
str zero, [state, #M4_COUNT] // state.m4_count = zero // 2
str zero, [state, #NUM_SHORTFALLS] // state.num_shortfalls = zero // 2
str zero, [state, #LONGEST_SHORTFALL] // state.longest_shortfall = zero // 2
mov shortfall_length, zero // shortfall_length = zero // 1
.endm
.macro await_sgpio
// Wait for, then clear, SGPIO exchange interrupt flag.
//
// Clobbers:
int_status .req r0
scratch .req r1
// The worst case timing is assumed to occur when reading the interrupt
// status register *just* misses the flag being set - so we include the
// cycles required to check it a second time.
//
// We also assume that we can spend a full 10 cycles doing an ldr from
// SGPIO the first time (2 for ldr, plus 8 for SGPIO-AHB bus latency),
// and still miss a flag that was set at the start of those 10 cycles.
//
// This latter asssumption is probably slightly pessimistic, since the
// sampling of the flag on the SGPIO side must occur some time after
// the ldr instruction begins executing on the M0. However, we avoid
// relying on any assumptions about the timing details of a read over
// the SGPIO to AHB bridge.
int_wait:
// Spin on the exchange interrupt status, shifting the slice A flag to the carry flag.
ldr int_status, [sgpio_int, #INT_STATUS] // int_status = SGPIO_STATUS_1 // 10, twice
lsr scratch, int_status, #1 // scratch = int_status >> 1 // 1, twice
bcc int_wait // if !carry: goto int_wait // 3, then 1
// Clear the interrupt pending bits that were set.
str int_status, [sgpio_int, #INT_CLEAR] // SGPIO_CLR_STATUS_1 = int_status // 8
.endm
.macro update_buf_ptr
// Update the address of the buffer segment we want to write to / read from.
ldr count, [state, #M0_COUNT] // count = state.m0_count // 2
mov buf_ptr, buf_mask // buf_ptr = buf_mask // 1
and buf_ptr, count // buf_ptr &= count // 1
add buf_ptr, buf_base // buf_ptr += buf_base // 1
.endm
.macro update_counts
// Update counts after successful SGPIO operation.
// Update the byte count and store the new value.
add count, #32 // count += 32 // 1
str count, [state, #M0_COUNT] // state.m0_count = count // 2
// We didn't have a shortfall, so the current shortfall length is zero.
mov shortfall_length, hi_zero // shortfall_length = hi_zero // 1
.endm
.macro handle_shortfall
// Handle a shortfall.
//
// Clobbers:
length .req r0
num .req r1
longest .req r1
limit .req r1
// Get current shortfall length from high register.
mov length, shortfall_length // length = shortfall_length // 1
// Is this a new shortfall?
cmp length, #0 // if length > 0: // 1
bgt extend_shortfall // goto extend_shortfall // 1 thru, 3 taken
// If so, increase the shortfall count.
ldr num, [state, #NUM_SHORTFALLS] // num = state.num_shortfalls // 2
add num, #1 // num += 1 // 1
str num, [state, #NUM_SHORTFALLS] // state.num_shortfalls = num // 2
extend_shortfall:
// Extend the length of the current shortfall, and store back in high register.
add length, #32 // length += 32 // 1
mov shortfall_length, length // shortfall_length = length // 1
// Is this now the longest shortfall?
ldr longest, [state, #LONGEST_SHORTFALL] // longest = state.longest_shortfall // 2
cmp length, longest // if length <= longest: // 1
blt loop // goto loop // 1 thru, 3 taken
str length, [state, #LONGEST_SHORTFALL] // state.longest_shortfall = length // 2
// Is this shortfall long enough to trigger a timeout?
ldr limit, [state, #SHORTFALL_LIMIT] // limit = state.shortfall_limit // 2
cmp limit, #0 // if limit == 0: // 1
beq loop // goto loop // 1 thru, 3 taken
cmp length, limit // if length < limit: // 1
blt loop // goto loop // 1 thru, 3 taken
// If so, reset mode to idle and return to idle loop.
mode .req r3
mov mode, #MODE_IDLE // mode = MODE_IDLE // 1
str mode, [state, #MODE] // state.mode = mode // 2
b idle // goto idle // 3
.endm
// Entry point. At this point, the libopencm3 startup code has set things up as // Entry point. At this point, the libopencm3 startup code has set things up as
// normal; .data and .bss are initialised, the stack is set up, etc. However, // normal; .data and .bss are initialised, the stack is set up, etc. However,
// we don't actually use any of that. All the code in this file would work // we don't actually use any of that. All the code in this file would work