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:
mb 2009-06-21 13:26:37 +00:00
parent 529ccaf841
commit aab089612f
2 changed files with 63 additions and 79 deletions

View File

@ -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)

View File

@ -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);