diff --git a/ports/arm/platforms/qemu_integratorcp/Makefile b/ports/arm/platforms/qemu_integratorcp/Makefile index 7243d1c..6bfe97b 100644 --- a/ports/arm/platforms/qemu_integratorcp/Makefile +++ b/ports/arm/platforms/qemu_integratorcp/Makefile @@ -23,7 +23,7 @@ QEMU=qemu-system-arm BUILD_DIR=build # Platform-specific object files -PLATFORM_OBJECTS = modules.o +PLATFORM_OBJECTS = modules.o uart.o PLATFORM_ASM_OBJECTS = startup.o # Port-specific object files diff --git a/ports/arm/platforms/qemu_integratorcp/uart.c b/ports/arm/platforms/qemu_integratorcp/uart.c new file mode 100644 index 0000000..4773004 --- /dev/null +++ b/ports/arm/platforms/qemu_integratorcp/uart.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2013, Kelvin Lawson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * \file + * UART implementation for non-hosted compiler toolchains. + * + * + * Some toolchains may be semi-hosted and implement these automatically + * for use within QEMU. + */ + +#include "atom.h" +#include "atommutex.h" +#include "atomport.h" +#include "uart.h" + + +/* Constants */ + +/** UART0 registers base address */ +#define UART0_ADDR 0x16000000 + +/** FR Register bits */ +#define UART_FR_RXFE 0x10 +#define UART_FR_TXFF 0x20 + +/** UART register access macros */ +#define UART_DR(baseaddr) (*(unsigned int *)(baseaddr)) +#define UART_FR(baseaddr) (*(((unsigned int *)(baseaddr))+6)) + + +/* Local data */ + +/* + * Semaphore for single-threaded access to UART device + */ +static ATOM_MUTEX uart_mutex; + +/* + * Initialised flag + */ +static int initialised = FALSE; + + +/* Forward declarations */ +static int uart_init (void); + + +/** + * \b uart_init + * + * Initialisation of UART driver. Creates a mutex that enforces + * single-threaded access to the UART. We poll register bits + * to check when space is available, which would not otherwise + * be thread-safe. + * + * @retval ATOM_OK Success + * @retval ATOM_ERROR Failed to create mutex + */ +static int uart_init (void) +{ + int status; + + /* Check we are not already initialised */ + if (initialised == FALSE) + { + /* Create a mutex for single-threaded UART access */ + if (atomMutexCreate (&uart_mutex) != ATOM_OK) + { + /* Mutex creation failed */ + status = ATOM_ERROR; + } + else + { + /* Success */ + initialised = TRUE; + status = ATOM_OK; + } + } + + /* Finished */ + return (status); +} + + +/** + * \b uart_read + * + * Simple polled UART read. + * + * @param[in] ptr Pointer to receive buffer + * @param[in] len Max bytes to read + * + * @retval Number of bytes read + * + */ +int uart_read (char *ptr, int len) +{ + int todo = 0; + + /* Check we are initialised */ + if (initialised == FALSE) + { + uart_init(); + } + + /* Check parameters */ + if ((ptr == NULL) || (len == 0)) + { + return 0; + } + + /* Block thread on private access to the UART */ + if (atomMutexGet(&uart_mutex, 0) == ATOM_OK) + { + /* Wait for not-empty */ + while(UART_FR(UART0_ADDR) & UART_FR_RXFE) + ; + + /* Read first byte */ + *ptr++ = UART_DR(UART0_ADDR); + + /* Loop over remaining bytes until empty */ + for (todo = 1; todo < len; todo++) + { + /* Quit if receive FIFO empty */ + if(UART_FR(UART0_ADDR) & UART_FR_RXFE) + { + break; + } + + /* Read next byte */ + *ptr++ = UART_DR(UART0_ADDR); + } + + /* Return mutex access */ + atomMutexPut(&uart_mutex); + } + + /* Return number of bytes read */ + return todo; +} + + +/** + * \b uart_write + * + * Simple polled UART write. + * + * @param[in] ptr Pointer to write buffer + * @param[in] len Number of bytes to write + * + * @retval Number of bytes written + */ +int uart_write (const char *ptr, int len) +{ + int todo; + + /* Check we are initialised */ + if (initialised == FALSE) + { + uart_init(); + } + + /* Check parameters */ + if ((ptr == NULL) || (len == 0)) + { + return 0; + } + + /* Block thread on private access to the UART */ + if (atomMutexGet(&uart_mutex, 0) == ATOM_OK) + { + /* Loop through all bytes to write */ + for (todo = 0; todo < len; todo++) + { + /* Wait for empty */ + while(UART_FR(UART0_ADDR) & UART_FR_TXFF) + ; + + /* Write byte to UART */ + UART_DR(UART0_ADDR) = *ptr++; + } + + /* Return mutex access */ + atomMutexPut(&uart_mutex); + } + + /* Return bytes-written count */ + return len; +} + diff --git a/ports/arm/platforms/qemu_integratorcp/uart.h b/ports/arm/platforms/qemu_integratorcp/uart.h new file mode 100644 index 0000000..57018c4 --- /dev/null +++ b/ports/arm/platforms/qemu_integratorcp/uart.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013, Kelvin Lawson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. No personal names or organizations' names associated with the + * Atomthreads project may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __ATOM_UART_H +#define __ATOM_UART_H + +/* UART driver APIs */ +extern int uart_read (char *ptr, int len); +extern int uart_write (const char *ptr, int len); + +#endif /* __ATOM_UART_H */ diff --git a/ports/arm/syscalls.c b/ports/arm/syscalls.c index 16c6a19..5e4c08e 100644 --- a/ports/arm/syscalls.c +++ b/ports/arm/syscalls.c @@ -37,20 +37,20 @@ * without newlib. Allows usage of printf() and friends as well as heap * allocation. * + * NOTE: Platform/BSP must implement uart_read() and uart_write(). + * + * NOTE: Platform/BSP linker script must define "end" and "heap_top" which are + * the heap base and top respectively. + * + * No file table is implemented. All file read/write operations are carried + * out on the UART driver, regardless of file descriptor. + * * Mostly based on code from http://balau82.wordpress.com * */ #include - -enum { - UART_FR_RXFE = 0x10, - UART_FR_TXFF = 0x20, - UART0_ADDR = 0x16000000, -}; - -#define UART_DR(baseaddr) (*(unsigned int *)(baseaddr)) -#define UART_FR(baseaddr) (*(((unsigned int *)(baseaddr))+6)) +#include "uart.h" /** @@ -70,7 +70,7 @@ extern int _write(int file, char *ptr, int len) __attribute__((weak)); /** * \b _close * - * Simple stub implementation. + * Simple stub implementation with no file table. All parameters ignored. * */ int _close(int file) @@ -82,11 +82,12 @@ int _close(int file) /** * \b _fstat * - * Simple stub implementation. + * Simple stub implementation. Always return character device. * */ int _fstat(int file, struct stat *st) { + /* Only UART supported, always return character-oriented device file */ st->st_mode = S_IFCHR; return 0; } @@ -95,7 +96,7 @@ int _fstat(int file, struct stat *st) /** * \b _isatty * - * Simple stub implementation. + * Simple stub implementation. Only UART supported so TTY always true. * */ int _isatty(int file) @@ -107,7 +108,7 @@ int _isatty(int file) /** * \b _lseek * - * Simple stub implementation. + * Simple stub implementation. All parameters ignored. * */ int _lseek(int file, int ptr, int dir) @@ -119,7 +120,7 @@ int _lseek(int file, int ptr, int dir) /** * \b _open * - * Simple stub implementation. + * Simple stub implementation with no file table. All parameters ignored. * */ int _open(const char *name, int flags, int mode) @@ -131,58 +132,52 @@ int _open(const char *name, int flags, int mode) /** * \b _read * - * Simple stub implementation. + * Simple read file implementation. Ignores file descriptor parameter + * and always reads from the UART driver. * + * @param[in] file File descriptor (parameter ignored) + * @param[in] ptr Pointer to receive buffer + * @param[in] len Max bytes to read + * + * @retval Number of bytes read */ int _read(int file, char *ptr, int len) { - int todo; - - if(len == 0) - return 0; - - while(UART_FR(UART0_ADDR) & UART_FR_RXFE) - ; - - *ptr++ = UART_DR(UART0_ADDR); - for (todo = 1; todo < len; todo++) - { - if(UART_FR(UART0_ADDR) & UART_FR_RXFE) - { - break; - } - *ptr++ = UART_DR(UART0_ADDR); - } - return todo; + /* Read from the UART driver, regardless of file descriptor */ + return (uart_read (ptr, len)); } /** * \b _write * - * Simple stub implementation. + * Simple write file implementation. Ignores file descriptor parameter + * and always writes to the UART driver. * + * @param[in] file File descriptor (parameter ignored) + * @param[in] ptr Pointer to write buffer + * @param[in] len Number of bytes to write + * + * @retval Number of bytes written */ int _write(int file, char *ptr, int len) { - int todo; - - for (todo = 0; todo < len; todo++) - { - while(UART_FR(UART0_ADDR) & UART_FR_TXFF) - ; - UART_DR(UART0_ADDR) = *ptr++; - } - - return len; + /* Write to the UART driver, regardless of file descriptor */ + return (uart_write (ptr, len)); } /** * \b _sbrk * - * Simple stub implementation. + * Simple heap implementation. * + * The platform/BSP must define "end" and "heap_top" which are the heap + * base and top respectively. + * + * @param[in] incr Chunk size + * + * @retval Pointer to allocated chunk start */ caddr_t _sbrk(int incr) { @@ -191,19 +186,26 @@ caddr_t _sbrk(int incr) static char *heap_end = 0; char *prev_heap_end; + /* First time in, initialise heap base using definition from linker script */ if (heap_end == 0) { heap_end = &end; } + + /* Save the previous heap base */ prev_heap_end = heap_end; + /* Check we have not passed the heap top */ if (heap_end + incr > &heap_top) { - /* Heap and stack collision */ + /* Heap top reached, failed to allocate */ return (caddr_t)0; } + /* New heap base */ heap_end += incr; + + /* Return pointer to previous base (where our allocation starts) */ return (caddr_t)prev_heap_end; } diff --git a/ports/avr/uart.c b/ports/avr/uart.c index 5d51231..763e38f 100644 --- a/ports/avr/uart.c +++ b/ports/avr/uart.c @@ -45,6 +45,8 @@ #endif +/* Local data */ + /* * Semaphore for single-threaded access to UART device */