Skip to content

Commit

Permalink
common/stm32/swo: apply clang-format to all touched files
Browse files Browse the repository at this point in the history
  • Loading branch information
ssimek committed Oct 17, 2024
1 parent bb8bf9e commit 0a26202
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 94 deletions.
3 changes: 1 addition & 2 deletions src/platforms/common/stm32/swo.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,7 @@ void swo_send_buffer(usbd_device *const dev, const uint8_t ep)
if (swo_itm_decoding) {
/* If we're in UART mode, hand as much as we can all at once */
if (swo_current_mode == swo_nrz_uart)
result = swo_itm_decode(
swo_buffer + swo_buffer_read_index, bytes_available);
result = swo_itm_decode(swo_buffer + swo_buffer_read_index, bytes_available);
/* Otherwise, if we're in Manchester mode, manage the amount moved the same as we do USB */
else
result = swo_itm_decode(swo_buffer + swo_buffer_read_index, MIN(bytes_available, SWO_ENDPOINT_SIZE));
Expand Down
3 changes: 1 addition & 2 deletions src/platforms/common/stm32/swo_manchester.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,7 @@ void swo_buffer_data(void)

/* Make sure we're sending the data if we've got more than an endpoint buffer's worth */
const uint16_t swo_buffer_bytes_available =
(swo_buffer_write_index - swo_buffer_read_index) &
(SWO_BUFFER_SIZE - 1U);
(swo_buffer_write_index - swo_buffer_read_index) & (SWO_BUFFER_SIZE - 1U);
if (swo_buffer_bytes_available >= SWO_ENDPOINT_SIZE) {
swo_send_buffer(usbdev, SWO_ENDPOINT);
}
Expand Down
159 changes: 69 additions & 90 deletions src/platforms/common/stm32/swo_manchester_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,11 @@
// Number of 16-bit samples captured for processing, the processing
// is triggered when half of the buffer is full, must be a power of two
#ifndef SWO_DMA_EDGE_SAMPLES
#define SWO_DMA_EDGE_SAMPLES 512
#define SWO_DMA_EDGE_SAMPLES 512
#endif

#define SWO_DMA_EDGE_MASK ((SWO_DMA_EDGE_SAMPLES)-1U)

#define SWO_BUFFER_MASK ((SWO_BUFFER_SIZE)-1U)
#define SWO_DMA_EDGE_MASK ((SWO_DMA_EDGE_SAMPLES) - 1U)
#define SWO_BUFFER_MASK ((SWO_BUFFER_SIZE) - 1U)

// Fixed length of a pulse that resets the decoder
// 72 MHz / 4096 = ~17.6 kHZ longest acceptable pulse
Expand All @@ -85,11 +84,11 @@
* Manchester decoder state
*/
static struct state {
uint16_t read_index; // index of next edge in dma_buf to process
uint16_t last_edge; // time of the last processed edge
uint32_t pulse_multiplier; // discriminator between long and short pulses (1.5x preamble time)
int32_t bit_buffer; // contains up to 32 decoded but unsent bits
uint8_t state; // state machine state (see enum below)
uint16_t read_index; // index of next edge in dma_buf to process
uint16_t last_edge; // time of the last processed edge
uint32_t pulse_multiplier; // discriminator between long and short pulses (1.5x preamble time)
int32_t bit_buffer; // contains up to 32 decoded but unsent bits
uint8_t state; // state machine state (see enum below)
} swo_state;

/*
Expand All @@ -98,14 +97,14 @@ static struct state {
* Even/odd states correspond to line high/low state
*/
enum {
ST_MIDH, // line high at mid-bit
ST_MIDL, // line low at mid-bit
ST_RESH, // line high after invalid pulse
ST_IDLE, // line idle
ST_INIT, // line high before initial half-bit
ST_INIL, // line low after init (does not count for output)
ST_BITH, // line high at bit boundary
ST_BITL, // line low at bit boundary
ST_MIDH, // line high at mid-bit
ST_MIDL, // line low at mid-bit
ST_RESH, // line high after invalid pulse
ST_IDLE, // line idle
ST_INIT, // line high before initial half-bit
ST_INIL, // line low after init (does not count for output)
ST_BITH, // line high at bit boundary
ST_BITL, // line low at bit boundary
};

// edge time buffer
Expand All @@ -117,24 +116,19 @@ static inline uint16_t swo_dma_write_index()
return SWO_DMA_EDGE_SAMPLES - DMA_CNDTR(SWO_DMA_BUS, SWO_DMA_EDGE_CHAN);
}


static inline void swo_buffer_write_multi(uint32_t bytes, unsigned count)
{
uint32_t write_index = swo_buffer_write_index;
uint8_t* buffer = swo_buffer;
uint8_t *buffer = swo_buffer;

if (write_index + 4 <= SWO_BUFFER_SIZE)
{
if (write_index + 4 <= SWO_BUFFER_SIZE) {
// use 32-bit write, it is (almost) safe even when count is less
// as if the read head is anywhere close, we'd be overflowing soon
// anyway
*(uint32_t*)&buffer[write_index] = bytes;
*(uint32_t *)&buffer[write_index] = bytes;
write_index += count;
}
else
{
while (count--)
{
} else {
while (count--) {
buffer[write_index++ & SWO_BUFFER_MASK] = bytes;
bytes >>= 8;
}
Expand All @@ -143,7 +137,6 @@ static inline void swo_buffer_write_multi(uint32_t bytes, unsigned count)
swo_buffer_write_index = write_index & SWO_BUFFER_MASK;
}


static inline void swo_buffer_write(uint8_t byte)
{
uint32_t write_index = swo_buffer_write_index;
Expand All @@ -159,7 +152,6 @@ static inline void swo_buffer_push(void)
NVIC_STIR = SWO_DMA_SW_IRQ;
}


/*
* Initializes and starts the decoder
*/
Expand All @@ -174,7 +166,7 @@ void swo_manchester_init(void)
// increasing resiliency of the input against noise
timer_ic_set_filter(SWO_TIM, TIM_IC1, TIM_IC_DTF_DIV_2_N_8);

// slave trigger on all TI1 edges (trigger start functionality not used,
// slave trigger on all TI1 edges (trigger start functionality not used,
// this just to enable the TRC event)
timer_slave_set_trigger(SWO_TIM, TIM_SMCR_TS_TI1F_ED);
timer_slave_set_mode(SWO_TIM, TIM_SMCR_SMS_TM);
Expand All @@ -190,7 +182,7 @@ void swo_manchester_init(void)

#if SWO_ADVANCED_RECOVERY
// optionally capture exact rising/falling edges on CH1/2,
// this is used only by the advanced recovery
// this is used only by the advanced recovery
timer_ic_set_input(SWO_TIM, TIM_IC1, TIM_IC_IN_TI1);
timer_ic_set_input(SWO_TIM, TIM_IC2, TIM_IC_IN_TI1);
timer_ic_set_polarity(SWO_TIM, TIM_IC1, TIM_IC_RISING);
Expand Down Expand Up @@ -267,8 +259,7 @@ void swo_manchester_deinit(void)
void SWO_DMA_SW_ISR(void)
{
// proceed only if there is a chance to send more data
if ((*USB_EP_REG(SWO_ENDPOINT) & USB_EP_TX_STAT) != USB_EP_TX_STAT_VALID)
{
if ((*USB_EP_REG(SWO_ENDPOINT) & USB_EP_TX_STAT) != USB_EP_TX_STAT_VALID) {
swo_send_buffer(usbdev, SWO_ENDPOINT);
}
}
Expand All @@ -293,7 +284,7 @@ void SWO_DMA_SW_ISR(void)
//#define SWO_DIAG_ISR (4 | 16)

// enable assembly optimizations
#define SWO_ASM_OPTIMIZATIONS 1
#define SWO_ASM_OPTIMIZATIONS 1

static inline void swo_diag_nibble(uint32_t v)
{
Expand Down Expand Up @@ -338,21 +329,21 @@ void SWO_TIM_ISR(void)
// careful, the lookup table order must match enum
static const uint8_t transitions[][4] = {
// ST_MIDH
{ ST_IDLE, ST_BITL, ST_MIDL, ST_IDLE },
{ST_IDLE, ST_BITL, ST_MIDL, ST_IDLE},
// ST_MIDL
{ ST_RESH, ST_BITH, ST_MIDH, ST_INIT },
{ST_RESH, ST_BITH, ST_MIDH, ST_INIT},
// ST_RESH (recovery reset)
{ ST_IDLE, ST_IDLE, ST_IDLE, ST_IDLE },
{ST_IDLE, ST_IDLE, ST_IDLE, ST_IDLE},
// ST_IDLE - always go to INIT, bit time is not known
{ ST_INIT, ST_INIT, ST_INIT, ST_INIT },
{ST_INIT, ST_INIT, ST_INIT, ST_INIT},
// ST_INIT - always go to INIL, bit time is not known
{ ST_INIL, ST_INIL, ST_INIL, ST_INIL },
{ST_INIL, ST_INIL, ST_INIL, ST_INIL},
// ST_INIL
{ ST_RESH, ST_BITH, ST_MIDH, ST_IDLE },
{ST_RESH, ST_BITH, ST_MIDH, ST_IDLE},
// ST_BITH
{ ST_IDLE, ST_MIDL, ST_IDLE, ST_IDLE },
{ST_IDLE, ST_MIDL, ST_IDLE, ST_IDLE},
// ST_BITL
{ ST_RESH, ST_MIDH, ST_INIT, ST_INIT },
{ST_RESH, ST_MIDH, ST_INIT, ST_INIT},
};

// clear all interrupts, we don't care about details at all
Expand All @@ -363,12 +354,10 @@ void SWO_TIM_ISR(void)
swo_buffer_write('<');
swo_diag_nibble(status >> 9);
swo_diag_nibble(status >> 1);
if (status & TIM_SR_TIF)
{
if (status & TIM_SR_TIF) {
swo_buffer_write('T');
}
if (status & TIM_SR_UIF)
{
if (status & TIM_SR_UIF) {
swo_buffer_write('U');
}
swo_buffer_write('>');
Expand All @@ -385,51 +374,47 @@ void SWO_TIM_ISR(void)
// number of samples available in the buffer
unsigned samples_available = (swo_dma_write_index() - read_index) & SWO_DMA_EDGE_MASK;

if (!samples_available)
{
if (!samples_available) {
// no data available
if (state != ST_IDLE)
{
if (state != ST_IDLE) {
// if the state machine is still running, use current count to measure time elapsed since the last pulse
// if enough time has elapsed, reset it, there is not much else we can do...
pulse_length = TIM_CNT(SWO_TIM) - last_edge;
if (pulse_length >= SWO_MAX_PULSE)
{
if (pulse_length >= SWO_MAX_PULSE) {
// modify the state in RAM directly
swo_state.state = ST_IDLE;
swo_state.pulse_multiplier = 0;
}
}

// this is a good time to push out any unflushed bytes the 32-bit buffer
#if !SWO_DIAG_ISR || (SWO_DIAG_ISR & (8 | 16))
uint32_t bit_buffer = swo_state.bit_buffer;
if (bit_buffer) // must not be zero, it would make the bitcount negative
if (bit_buffer) // must not be zero, it would make the bitcount negative
{
// 31 - CTZ(bit_buffer) == number of bits shifted into the buffer (because of the terminator bit)
unsigned bit_count = 31 - __builtin_ctz(bit_buffer);
// full bytes and unaligned (yet unsent) bits
unsigned bytes_count = bit_count >> 3;
unsigned unaligned_count = bit_count & 7;
// keep just the remaining bits in the register, overwriting the rest
// with a new terminator
// with a new terminator
uint32_t terminator = 1u << 31 >> unaligned_count;
swo_state.bit_buffer = (bit_buffer | terminator) & ~(terminator - 1);
// align the full bytes to be sent at LSB
bit_buffer >>= 32 - bit_count;

#if !SWO_DIAG_ISR || (SWO_DIAG_ISR & 8)
swo_buffer_write_multi(bit_buffer, bytes_count);
#endif
#if SWO_DIAG_ISR & 16
while (bytes_count--)
{
while (bytes_count--) {
swo_diag_nibble(swo_buffer_write_index);
}
#endif
}
#endif

// no need to go deeper, just trigger USB processing
swo_buffer_push();
return;
Expand All @@ -447,8 +432,7 @@ void SWO_TIM_ISR(void)

// inner processing loop - this has to be as fast as possible,
// every clock counts
do
{
do {
pulse_length = swo_dma_edge_samples[read_index++] - last_edge;
read_index &= SWO_DMA_EDGE_MASK;
last_edge += pulse_length;
Expand All @@ -461,21 +445,19 @@ void SWO_TIM_ISR(void)
#if SWO_ASM_OPTIMIZATIONS
// this is pretty bizarre, but GCC insists on jumping back and forth to
// handle the overflow state instead of using ite eq
__asm__ (
"cmp %[h], #0\n"
"ite eq\n"
"moveq %[tran], %[l], lsr #30\n"
"movne %[tran], #3\n"
: [tran] "=r" (tran)
: [h] "r" ((uint32_t)(pulse_mul >> 32)), [l] "r" ((uint32_t)pulse_mul)
);
__asm__("cmp %[h], #0\n"
"ite eq\n"
"moveq %[tran], %[l], lsr #30\n"
"movne %[tran], #3\n"
: [tran] "=r"(tran)
: [h] "r"((uint32_t)(pulse_mul >> 32)), [l] "r"((uint32_t)pulse_mul));
#else
tran = (uint32_t)(pulse_mul >> 32) ? 3 : (uint32_t)pulse_mul >> 30;
#endif
state = transitions[state][tran];

#if SWO_DIAG_ISR & 32
swo_buffer_write((state & 1 ? "^'\"!": "v._-")[tran]);
swo_buffer_write((state & 1 ? "^'\"!" : "v._-")[tran]);
#endif

#if SWO_DIAG_ISR & 64
Expand All @@ -485,49 +467,46 @@ void SWO_TIM_ISR(void)
// handle states requiring extra actions, primarily bit writing
#if SWO_ASM_OPTIMIZATIONS
bool output;
__asm__ goto (
"cmp %[state], %[ST_MIDL]\n" // C = state == MIDL
"bhi %l[not_bit_state]\n" // state > MIDL
// shift C into bit_buffer
// shift LSB into C to know if we have full output ready
"rrxs %[bit_buffer], %[bit_buffer]"
// NOTE: bit_buffer is passed in as an input operand - this seems to be
__asm__ goto("cmp %[state], %[ST_MIDL]\n" // C = state == MIDL
"bhi %l[not_bit_state]\n" // state > MIDL
// shift C into bit_buffer
// shift LSB into C to know if we have full output ready
"rrxs %[bit_buffer], %[bit_buffer]"
// NOTE: bit_buffer is passed in as an input operand - this seems to be
// the only way to prevent the compiler from generating
// spurious move instructions before and/or after the inline block
// it works in practice, but is deep in the UB territory...
: "=@cccs" (output)
: [bit_buffer] "r" (bit_buffer), [state] "r" (state), [ST_MIDL] "i" (ST_MIDL)
: "=@cccs"(output)
: [bit_buffer] "r"(bit_buffer), [state] "r"(state), [ST_MIDL] "i"(ST_MIDL)
:
: not_bit_state
);
: not_bit_state);
#else
// just to make it comparable with the assembly version :)
if (state > ST_MIDL) { goto not_bit_state; }
if (state > ST_MIDL) {
goto not_bit_state;
}
bool output = bit_buffer & 1;
bit_buffer = bit_buffer >> 1 | ((state == ST_MIDL) << 31);
#endif
// mid-bit transition == output bit
if (output)
{
if (output) {
// we have shifted out the initial bit,
// meaning full 32 bits have been collected
//swo_buffer_write(swo_buf_wx);
#if !SWO_DIAG_ISR || (SWO_DIAG_ISR & 8)
swo_buffer_write_multi(bit_buffer, 4);
#endif
#if SWO_DIAG_ISR & 16
for (int i = 0; i < 4; i++)
{
for (int i = 0; i < 4; i++) {
swo_diag_nibble(swo_buffer_write_index);
}
#endif
bit_buffer = 1 << 31;
}
continue;

not_bit_state:
if (state == ST_INIL)
{
not_bit_state:
if (state == ST_INIL) {
// calculate pulse multipler that, when multiplied by an actual pulse
// length, gets it into three categories in top 2 bits
// 00 - < 0.75x of the original, considered a glitch
Expand All @@ -550,5 +529,5 @@ void SWO_TIM_ISR(void)
swo_buffer_push();

// store the state for next run
swo_state = (struct state){ read_index, last_edge, pulse_multiplier, bit_buffer, state };
swo_state = (struct state){read_index, last_edge, pulse_multiplier, bit_buffer, state};
}

0 comments on commit 0a26202

Please sign in to comment.