Update the optimized AVR8 example implementation.
git-svn-id: svn://svn.openwrt.org/openwrt/packages@16532 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
parent
529ccaf841
commit
aab089612f
@ -23,8 +23,6 @@
|
||||
*/
|
||||
|
||||
#include "ucmb.h"
|
||||
#include "util.h"
|
||||
#include "uart.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <avr/io.h>
|
||||
@ -41,6 +39,17 @@
|
||||
#define __naked __attribute__((__naked__))
|
||||
#undef __used
|
||||
#define __used __attribute__((__used__))
|
||||
#undef __noret
|
||||
#define __noret __attribute__((__noreturn__))
|
||||
#undef offsetof
|
||||
#define offsetof(type, member) ((size_t)&((type *)0)->member)
|
||||
#undef unlikely
|
||||
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||
#undef mb
|
||||
#define mb() __asm__ __volatile__("" : : : "memory") /* memory barrier */
|
||||
#ifndef ucmb_errorlog
|
||||
# define ucmb_errorlog(message) do { /* nothing */ } while (0)
|
||||
#endif
|
||||
|
||||
|
||||
struct ucmb_message_hdr {
|
||||
@ -74,6 +83,7 @@ static uint8_t ucmb_buf[sizeof(struct ucmb_message_hdr) +
|
||||
static uint16_t ucmb_buf_ptr __used;
|
||||
static struct ucmb_status status_buf __used;
|
||||
static uint16_t ucmb_send_message_len __used;
|
||||
static uint8_t ucmb_received_message;
|
||||
|
||||
/* The current IRQ handler */
|
||||
static void (*ucmb_interrupt_handler)(void) __used;
|
||||
@ -242,35 +252,12 @@ UCMB_IRQ_EPILOGUE /* reti */
|
||||
"st_listen_have_full_packet: \n"
|
||||
" ; We have the full packet. Any SPI transfer is stopped \n"
|
||||
" ; while we are processing the packet, so this \n"
|
||||
" ; is a slowpath. Branch to a C function. \n"
|
||||
" clr __zero_reg__ \n"
|
||||
" push r18 \n"
|
||||
" push r19 \n"
|
||||
" push r20 \n"
|
||||
" push r21 \n"
|
||||
" push r22 \n"
|
||||
" push r23 \n"
|
||||
" push r24 \n"
|
||||
" push r25 \n"
|
||||
" push r26 \n"
|
||||
" push r27 \n"
|
||||
" push r30 \n"
|
||||
" push r31 \n"
|
||||
" push __tmp_reg__ \n"
|
||||
" rcall ucmb_received_packet \n"
|
||||
" pop __tmp_reg__ \n"
|
||||
" pop r31 \n"
|
||||
" pop r30 \n"
|
||||
" pop r27 \n"
|
||||
" pop r26 \n"
|
||||
" pop r25 \n"
|
||||
" pop r24 \n"
|
||||
" pop r23 \n"
|
||||
" pop r22 \n"
|
||||
" pop r21 \n"
|
||||
" pop r20 \n"
|
||||
" pop r19 \n"
|
||||
" pop r18 \n"
|
||||
" ; is a slowpath. \n"
|
||||
" ; Disable SPI and pass control to ucmb_work to \n"
|
||||
" ; handle the message. \n"
|
||||
" cbi %[_SPCR], %[_SPIE] \n"
|
||||
" ldi r18, 1 \n"
|
||||
" sts ucmb_received_message, r18 \n"
|
||||
" rjmp st_listen_out \n"
|
||||
: /* none */
|
||||
: [sizeof_buf] "i" (sizeof(ucmb_buf))
|
||||
@ -279,6 +266,8 @@ UCMB_IRQ_EPILOGUE /* reti */
|
||||
, [offsetof_hdr_magic] "M" (offsetof(struct ucmb_message_hdr, magic))
|
||||
, [offsetof_hdr_len] "M" (offsetof(struct ucmb_message_hdr, len))
|
||||
, [_SPDR] "M" (_SFR_IO_ADDR(SPDR))
|
||||
, [_SPCR] "M" (_SFR_IO_ADDR(SPCR))
|
||||
, [_SPIE] "i" (SPIE)
|
||||
, [_UCMB_MAGIC] "i" (UCMB_MAGIC)
|
||||
: "memory"
|
||||
);
|
||||
@ -439,35 +428,10 @@ UCMB_IRQ_EPILOGUE /* reti */
|
||||
"invalid_status_magic: \n"
|
||||
"faulty_status_code: \n"
|
||||
" ; Branch to the C error handler \n"
|
||||
" ; The handler does not return, so we don't need to \n"
|
||||
" ; push/pop the registers. \n"
|
||||
" clr __zero_reg__ \n"
|
||||
" push r18 \n"
|
||||
" push r19 \n"
|
||||
" push r20 \n"
|
||||
" push r21 \n"
|
||||
" push r22 \n"
|
||||
" push r23 \n"
|
||||
" push r24 \n"
|
||||
" push r25 \n"
|
||||
" push r26 \n"
|
||||
" push r27 \n"
|
||||
" push r30 \n"
|
||||
" push r31 \n"
|
||||
" push __tmp_reg__ \n"
|
||||
" rcall ucmb_received_faulty_status \n"
|
||||
" pop __tmp_reg__ \n"
|
||||
" pop r31 \n"
|
||||
" pop r30 \n"
|
||||
" pop r27 \n"
|
||||
" pop r26 \n"
|
||||
" pop r25 \n"
|
||||
" pop r24 \n"
|
||||
" pop r23 \n"
|
||||
" pop r22 \n"
|
||||
" pop r21 \n"
|
||||
" pop r20 \n"
|
||||
" pop r19 \n"
|
||||
" pop r18 \n"
|
||||
" rjmp st_retrstatus_out \n"
|
||||
" rjmp ucmb_received_faulty_status \n"
|
||||
: /* none */
|
||||
: [sizeof_ucmb_status] "M" (sizeof(struct ucmb_status))
|
||||
, [offsetof_status_magic] "M" (offsetof(struct ucmb_status, magic))
|
||||
@ -479,13 +443,33 @@ UCMB_IRQ_EPILOGUE /* reti */
|
||||
);
|
||||
}
|
||||
|
||||
/* We received a full packet. This is called from assembly code. */
|
||||
static void __used ucmb_received_packet(void)
|
||||
/* We received a status report with an error condition.
|
||||
* This is called from assembly code. The function does not return. */
|
||||
static void __used __noret ucmb_received_faulty_status(void)
|
||||
{
|
||||
/* The master sent us a status report with an error code.
|
||||
* Something's wrong with us. Print a status message and
|
||||
* get caught by the watchdog, yummy.
|
||||
*/
|
||||
|
||||
cli();
|
||||
wdt_disable();
|
||||
wdt_enable(WDTO_15MS);
|
||||
ucmb_errorlog("UCMB: Received faulty status report. Triggering reset.");
|
||||
while (1) {
|
||||
/* "It's Coming Right For Us!" */
|
||||
}
|
||||
}
|
||||
|
||||
void ucmb_work(void)
|
||||
{
|
||||
struct ucmb_message_hdr *hdr;
|
||||
struct ucmb_message_footer *footer;
|
||||
uint16_t payload_len;
|
||||
|
||||
if (!ucmb_received_message)
|
||||
return;
|
||||
|
||||
hdr = (struct ucmb_message_hdr *)ucmb_buf;
|
||||
payload_len = hdr->len;
|
||||
|
||||
@ -508,7 +492,7 @@ static void __used ucmb_received_packet(void)
|
||||
ucmb_buf_ptr++;
|
||||
|
||||
if (unlikely(status_buf.code != UCMB_STAT_OK))
|
||||
return; /* Corrupt message. Don't pass it to user code. */
|
||||
goto out; /* Corrupt message. Don't pass it to user code. */
|
||||
|
||||
ucmb_send_message_len = ucmb_rx_message(
|
||||
ucmb_buf + sizeof(struct ucmb_message_hdr),
|
||||
@ -525,24 +509,12 @@ static void __used ucmb_received_packet(void)
|
||||
ucmb_send_message_len += sizeof(struct ucmb_message_hdr) +
|
||||
sizeof(struct ucmb_message_footer);
|
||||
}
|
||||
}
|
||||
|
||||
/* We received a status report with an error condition.
|
||||
* This is called from assembly code. */
|
||||
static void __used ucmb_received_faulty_status(void)
|
||||
{
|
||||
/* The master sent us a status report with an error code.
|
||||
* Something's wrong with us. Print a status message and
|
||||
* get caught by the watchdog, yummy.
|
||||
*/
|
||||
|
||||
cli();
|
||||
wdt_disable();
|
||||
uart_logmsg("UCMB: Received faulty status report. Triggering reset.");
|
||||
wdt_enable(WDTO_15MS);
|
||||
while (1) {
|
||||
/* "It's Coming Right For Us!" */
|
||||
}
|
||||
out:
|
||||
ucmb_received_message = 0;
|
||||
mb();
|
||||
/* Re-enable SPI */
|
||||
SPCR |= (1 << SPIE);
|
||||
}
|
||||
|
||||
void ucmb_init(void)
|
||||
|
@ -7,6 +7,11 @@
|
||||
/* Max length of the message payload. */
|
||||
#define UCMB_MAX_MSG_LEN (128 * 64 / 8 + 16)
|
||||
|
||||
/* Error logs: If you want UCMB error log messages, define
|
||||
* ucmb_errorlog(message_string_literal)
|
||||
* somewhere. If you don't define it, UCMB will be compiled
|
||||
* without error messages. */
|
||||
|
||||
/* ucmb_rx_message - Message receive callback.
|
||||
* Define this elsewhere. It's called on successful retrieval
|
||||
* of a new message.
|
||||
@ -14,10 +19,17 @@
|
||||
* message payload into the "payload" buffer and return the number
|
||||
* of bytes to transmit. If no reply message is needed, return 0.
|
||||
* Note that the "payload" buffer always has a size of UCMB_MAX_MSG_LEN.
|
||||
* This function is called with interrupts enabled.
|
||||
*/
|
||||
extern uint16_t ucmb_rx_message(uint8_t *payload,
|
||||
uint16_t payload_length);
|
||||
|
||||
/* ucmb_work - Frequently call this from the mainloop.
|
||||
* Must not be called from interrupt context.
|
||||
* Must not be called with interrupts disabled.
|
||||
*/
|
||||
void ucmb_work(void);
|
||||
|
||||
/* Initialize the UCMB subsystem. */
|
||||
void ucmb_init(void);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user