diff options
author | Jeff Johnston <jjohnstn@redhat.com> | 2014-12-15 20:17:39 +0000 |
---|---|---|
committer | Jeff Johnston <jjohnstn@redhat.com> | 2014-12-15 20:17:39 +0000 |
commit | 68a910123726e7868baf89cac9038b4dbb22f612 (patch) | |
tree | 108b63e655003a7d58a3cc6f252ab2e6ace706d1 /libgloss/or1k/include | |
parent | d1219c0e89d2dc4ac865889cbd23f5e4c64d86e5 (diff) | |
download | cygnal-68a910123726e7868baf89cac9038b4dbb22f612.tar.gz cygnal-68a910123726e7868baf89cac9038b4dbb22f612.tar.bz2 cygnal-68a910123726e7868baf89cac9038b4dbb22f612.zip |
2014-12-15 Stefan Wallentowitz <stefan.wallentowitz@tum.de>
* or1k/Makefile.in: Add libor1k
* or1k/README: New file
* or1k/caches-asm.S: New file
* or1k/exceptions-asm.S: New file
* or1k/exceptions.c: New file
* or1k/impure.c: New file
* or1k/include/or1k-nop.h: New file
* or1k/include/or1k-support.h: New file
* or1k/interrupts-asm.S: New file
* or1k/interrupts.c: New file
* or1k/mmu-asm.S: New file
* or1k/or1k-internals.h: New file
* or1k/or1k_uart.c: New file
* or1k/or1k_uart.h: New file
* or1k/outbyte.S: New file
* or1k/sbrk.c: New file
* or1k/sync-asm.S: New file
* or1k/syscalls.c: New file
* or1k/timer.c: New file
* or1k/util.c: New file
Diffstat (limited to 'libgloss/or1k/include')
-rw-r--r-- | libgloss/or1k/include/or1k-nop.h | 35 | ||||
-rw-r--r-- | libgloss/or1k/include/or1k-support.h | 665 |
2 files changed, 700 insertions, 0 deletions
diff --git a/libgloss/or1k/include/or1k-nop.h b/libgloss/or1k/include/or1k-nop.h new file mode 100644 index 000000000..0d432dad4 --- /dev/null +++ b/libgloss/or1k/include/or1k-nop.h @@ -0,0 +1,35 @@ +/* or1k-asm.h -- OR1K assembly helper macros + + Copyright (c) 2014 OpenRISC Project Maintainers + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following condition + is met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + COPYRIGHT HOLDER 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 __OR1K_NOP_H__ +#define __OR1K_NOP_H__ + +#define OR1K_NOP_K_NOP 0x0 +#define OR1K_NOP_K_EXIT 0x1 +#define OR1K_NOP_K_PUTC 0x4 +#define OR1K_NOP_K_EXIT_QUIET 0xc + +#endif diff --git a/libgloss/or1k/include/or1k-support.h b/libgloss/or1k/include/or1k-support.h new file mode 100644 index 000000000..c29b064be --- /dev/null +++ b/libgloss/or1k/include/or1k-support.h @@ -0,0 +1,665 @@ +/* Copyright (c) 2014 Authors + * + * Contributor Julius Baxter <julius.baxter@orsoc.se> + * Contributor Stefan Wallentowitz <stefan.wallentowitz@tum.de> + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + +/* -------------------------------------------------------------------------- */ +/* This program is commented throughout in a fashion suitable for processing +with Doxygen. */ +/* -------------------------------------------------------------------------- */ + +#include <stdint.h> + +#ifndef __OR1K_SUPPORT_H__ +#define __OR1K_SUPPORT_H__ + +/*! +* \defgroup or1k_macros OR1K macros +* @{ +*/ + +/*! +* Access byte-sized memory mapped register +* +* Used to access a byte-sized memory mapped register. It avoids usage errors +* when not defining register addresses volatile and handles casting correctly. +* +* Example for both read and write: +* +* \code +* uint8_t status = REG8(IPBLOCK_STATUS_REG_ADDR); +* REG8(IPBLOCK_ENABLE) = 1; +* \endcode +* +* \param add Register address +*/ +#define REG8(add) *((volatile unsigned char *) (add)) + +/*! +* Access halfword-sized memory mapped register +* +* Used to access a 16 byte-sized memory mapped register. It avoids usage errors +* when not defining register addresses volatile and handles casting correctly. +* +* See REG8() for an example. +* +* \param add Register address +*/ +#define REG16(add) *((volatile unsigned short *) (add)) + +/*! +* Access word-sized memory mapped register +* +* Used to access a word-sized memory mapped register. It avoids usage errors +* when not defining register addresses volatile and handles casting correctly. +* +* See REG8() for an example. +* +* \param add Register address +*/ +#define REG32(add) *((volatile unsigned long *) (add)) +/*! +* @} +*/ + +/*! +* \defgroup or1k_interrupts OR1K interrupt control +* +* Interrupt control function prototypes +* +* @{ +*/ + +/*! Function pointer to interrupt handler functions */ +typedef void (*or1k_interrupt_handler_fptr)(void* data); + +/*! +* Add interrupt handler for interrupt line +* +* Registers a callback function for a certain interrupt line. +* +* \param line Interrupt line/id to register a handler for +* \param handler Handler to register +* \param data Data value passed to the handler +*/ +void or1k_interrupt_handler_add(uint32_t line, + or1k_interrupt_handler_fptr handler, + void* data); + +/*! +* Enable interrupts from a given line +* +* Unmask the given interrupt line. It is also important to enable interrupts +* in general, e.g., using or1k_interrupts_enable(). +* +* \param line Interrupt line to enable +*/ +void or1k_interrupt_enable(int line); + +/*! +* Disable interrupts from a given line +* +* Mask given interrupt line. It can be unmasked using or1k_interrupt_enable(). +* +* \param line Interrupt line to disable +*/ +void or1k_interrupt_disable(int line); + +/*! +* Disable interrupts +* +* This disables the interrupt exception. This is sufficient to disable all +* interrupts. It does not change the mask register (which is modified using +* or1k_interrupt_enable() and or1k_interrupt_disable()). +* +* The interrupt exception can be enabled using or1k_interrupts_enable(). +* +* Finally, the status of the interrupt exception enable flag is returned by +* this function. That allows to call this function even if interrupts are +* already disabled. To restore the value of the interrupt exception enable +* flag, use the or1k_interrupts_restore() function. That way you avoid to +* accidentally enable interrupts. Example: +* +* \code +* void f() { +* uint32_t interrupt_status = or1k_interrupts_disable(); +* // do something +* or1k_interrupts_restore(status); +* } +* \endcode +* +* This code will preserve the original status of the interrupt enable flag. +* +* \return Interrupt exception enable flag before call +*/ +uint32_t or1k_interrupts_disable(void); + +/*! +* Enable interrupt exception +* +* Enable the interrupt exception. Beside the interrupt exception, it is also +* necessary to enable the individual interrupt lines using +* or1k_interrupt_enable(). +* +* You should avoid using this function together with or1k_interrupts_disable() +* to guard atomic blocks as it unconditionally enables the interrupt +* exception (see documentation of or1k_interrupts_disable()). +*/ +void or1k_interrupts_enable(void); + +/*! +* Restore interrupt exception enable flag +* +* This function restores the given status to the processor. +* or1k_interrupts_restore(0) is identical to or1k_interrupts_disable() and +* or1k_interrupts_restore(SPR_SR_IEE) is identical to or1k_interrupts_enable(). +* +* It is for example used to guard an atomic block and restore the original +* status of the interrupt exception enable flag as returned by +* or1k_interrupts_disable(). See the documentation of or1k_interrupts_disable() +* for a usage example. +* +* \param status Status of the flag to restore +*/ +void or1k_interrupts_restore(uint32_t status); + +/*! + * Disable timer and interrupt exception + * + * This function disables the timer and interrupt exception to guard critical + * sections. It returns the status of the enable bits before the critical + * section, that is restored with or1k_critical_end(). + * + * Example: + * \code + * ... + * uint32_t status = or1k_critical_start(); + * // critical part + * or1k_critical_end(status); + * ... + * \endcode + * + * \return Status of timer and interrupt exception at time of call + */ +uint32_t or1k_critical_begin(); + +/*! + * Enable timer and interrupt exception + * + * Restore the timer and interrupt exception enable. The restore value is the + * return value from or1k_critical_start(). + * + * \param restore Interrupt and timer exception enable restore value + */ +void or1k_critical_end(uint32_t restore); +/*! +* @} +*/ + +/*! +* \defgroup or1k_exception Exception handling +* @{ +*/ +/*! Function pointer to an exception handler function */ +typedef void (*or1k_exception_handler_fptr)(void); + +/*! +* Register exception handler +* +* Register an exception handler for the given exception id. This handler is +* in the following then called when the exception occurs. You can thereby +* individually handle those exceptions. +* +* \param id Exception id +* \param handler Handler callback +*/ +void or1k_exception_handler_add(int id, or1k_exception_handler_fptr handler); +/*! +* @} +*/ + +/*! +* \defgroup or1k_spr SPR access +* @{ +*/ + +/*! +* Move value to special purpose register +* +* Move data value to a special purpose register +* +* \param spr SPR identifier, see spr-defs.h for macros +* \param value value to move to SPR +*/ +static inline void or1k_mtspr (uint32_t spr, uint32_t value) +{ + __asm__ __volatile__ ("l.mtspr\t\t%0,%1,0": : "r" (spr), "r" (value)); +} + +/*! +* Copy value from special purpose register +* +* Copy a data value from the given special purpose register. +* +* \param spr SPR identifier, see spr-defs.h for macros +* \return SPR data value +*/ +static inline uint32_t or1k_mfspr (uint32_t spr) { + uint32_t value; + __asm__ __volatile__ ("l.mfspr\t\t%0,%1,0" : "=r" (value) : "r" (spr)); + return value; +} +/*! +* @} +*/ + +/*! +* \defgroup or1k_util Miscellaneous utility functions +* +* @{ +*/ + +/*! +* Report value to simulator +* +* Uses the built-in simulator functionality. +* +* \param value Value to report +*/ +void or1k_report (unsigned long int value); + +/*! +* Get (pseudo) random number +* +* This should return pseudo-random numbers, based on a Galois LFSR. +* +* \return (Pseudo) Random number +*/ +unsigned long int or1k_rand(void); + +/*! + * Register UART callback + * + * This function sets a callback function that is called when a character is + * received via UART. The callback function has no return and a gets the + * character as parameter. When a character is received, the function is called. + * + * Example (UART echo): + * \code + * void uart_in(char c) { + * printf("%c", c); // Echo + * } + * + * int main() { + * or1k_uart_set_read_cb(&uart_in); + * or1k_interrupts_enable(); + * + * while (1) {} + * } + * \endcode + */ +void or1k_uart_set_read_cb(void (*cb)(char c)); +/*! +* @} +*/ + +/*! +* \defgroup or1k_cache Cache control +* +* @{ +*/ + +/*! +* Enable instruction cache +*/ +void or1k_icache_enable(void); + +/*! +* Disable instruction cache +*/ +void or1k_icache_disable(void); + +/*! +* Flush instruction cache +* +* Invalidate instruction cache entry +* +* \param entry Entry to invalidate +*/ +void or1k_icache_flush(uint32_t entry); + +/*! +* Enable data cache +*/ +void or1k_dcache_enable(void); + +/*! +* Disable data cache +*/ +void or1k_dcache_disable(void); + +/*! +* Flush data cache +* +* Invalidate data cache entry +* +* \param entry Entry to invalidate +*/ +void or1k_dcache_flush(unsigned long entry); +/*! +* @} +*/ + +/*! +* \defgroup or1k_mmu MMU control +* @{ +*/ + +/*! +* Enable instruction MMU +*/ +void or1k_immu_enable(void); + +/*! +* Disable instruction MMU +*/ +void or1k_immu_disable(void); + +/*! +* Enable data MMU +*/ +void or1k_dmmu_enable(void); + +/*! +* Disable data MMU +*/ +void or1k_dmmu_disable(void); +/*! +* @} +*/ + +/*! +* \defgroup or1k_timer Timer control +* +* The tick timer can be used for time measurement, operating system scheduling +* etc. By default it is initialized to continuously count the ticks of a +* certain period after calling or1k_timer_init(). The period can later be +* changed using or1k_timer_set_period(). +* +* The timer is controlled using or1k_timer_enable(), or1k_timer_disable(), +* or1k_timer_restore(), or1k_timer_pause(). After initialization it is required +* to enable the timer the first time using or1k_timer_enable(). +* or1k_timer_disable() only disables the tick timer interrupts, it does not +* disable the timer counting. If you plan to use a pair of or1k_timer_disable() +* and or1k_timer_enable() to protect sections of your code against interrupts +* you should use or1k_timer_disable() and or1k_timer_restore(), as it may be +* possible that the timer interrupt was not enabled before disabling it, +* enable would then start it unconditionally. or1k_timer_pause() pauses the +* counting. +* +* In the default mode you can get the tick value using or1k_timer_get_ticks() +* and reset this value using or1k_timer_reset_ticks(). +* +* Example for using the default mode: +* +* \code +* int main() { +* uint32_t ticks = 0; +* uint32_t timerstate; +* or1k_timer_init(100); +* or1k_timer_enable(); +* while (1) { +* while (ticks == or1k_timer_get_ticks()) { } +* timerstate = or1k_timer_disable(); +* // do something atomar +* or1k_timer_restore(timerstate); +* if (ticks == 100) { +* printf("A second elapsed\n"); +* or1k_timer_reset_ticks(); +* ticks = 0; +* } +* } +* } +* \endcode +* +* It is possible to change the mode of the tick timer using +* or1k_timer_set_mode(). Allowed values are the correct bit pattern (including +* the bit positions) for the TTMR register, it is recommended to use the macros +* defined in spr-defs.h. For example, implementing an operating system with +* scheduling decisions of varying duration favors the implementation of single +* run tick timer. Here, each quantum is started before leaving the operating +* system kernel. The counter can be restarted with or1k_timer_reset(). +* Example: +* +* \code +* void tick_handler(void) { +* // Make schedule decision +* // and set new thread +* or1k_timer_reset(); +* // End of exception, new thread will run +* } +* +* int main() { +* // Configure operating system and start threads.. +* +* // Configure timer +* or1k_timer_init(50); +* or1k_timer_set_handler(&tick_handler); +* or1k_timer_set_mode(SPR_TTMR_SR); +* or1k_timer_enable(); +* +* // Schedule first thread and die.. +* } +* \endcode +* +* @{ +*/ + +/*! +* Initialize tick timer +* +* This initializes the tick timer in default mode (see \ref or1k_timer for +* details). +* +* \param hz Initial period of the tick timer +* \return 0 if successful, -1 if timer not present +*/ +int or1k_timer_init(unsigned int hz); + +/*! +* Set period of timer +* +* Set the period of the timer to a value in Hz. The frequency from the board +* support package is used to determine the match value. +*/ +void or1k_timer_set_period(uint32_t hz); + +/*! +* Replace the timer interrupt handler +* +* By default the tick timer is used to handle timer ticks. The user can replace +* this with an own handler for example when implementing an operating system. +* +* \param handler The callback function pointer to the handler +*/ +void or1k_timer_set_handler(void (*handler)(void)); + +/*! +* Set timer mode +* +* The timer has different modes (see architecture manual). The default is to +* automatically restart counting (SPR_TTMR_RT), others are single run +* (SPR_TTMR_SR) and continuous run (SPR_TTMR_CR). +* +* \param mode a valid mode (use definitions from spr-defs.h as it is important +* that those are also at the correct position in the bit field!) +*/ +void or1k_timer_set_mode(uint32_t mode); + +/*! +* Enable timer interrupt +* +* Enable the timer interrupt exception, independent of the status before. +* If you want to enable the timer conditionally, for example to implement a +* non-interruptible sequence of code, you should use or1k_timer_restore(). See +* the description of or1k_timer_disable() for more details. +* +* The enable will also restore the mode if the timer was paused previously. +*/ +void or1k_timer_enable(void); + +/*! +* Disable timer interrupt +* +* This disables the timer interrupt exception and returns the state of the +* interrupt exception enable flag before the call. This can be used with +* or1k_timer_restore() to implement sequences of code that are not allowed to +* be interrupted. Using or1k_timer_enable() will unconditionally enable the +* interrupt independent of the state before calling or1k_timer_disable(). +* For an example see \ref or1k_timer. +* +* \return Status of timer interrupt before call +*/ +uint32_t or1k_timer_disable(void); + +/*! +* Restore timer interrupt exception flag +* +* Restores the timer interrupt exception flag as returned by +* or1k_timer_disable(). See the description of or1k_timer_disable() and \ref +* or1k_timer for details and an example. +* +* \param sr_tee Status of timer interrupt +*/ +void or1k_timer_restore(uint32_t sr_tee); + +/*! +* Pause timer counter +* +* Pauses the counter of the tick timer. The counter will hold its current value +* and it can be started again with or1k_timer_enable() which will restore the +* configured mode. +*/ +void or1k_timer_pause(void); + +/*! +* Reset timer counter +*/ +void or1k_timer_reset(void); + +/*! +* Get timer ticks +* +* Get the global ticks of the default configuration. This will increment the +* tick counter according to the preconfigured period. +* +* \return Current value of ticks +*/ +unsigned long or1k_timer_get_ticks(void); + +/*! +* Reset timer ticks +* +* Resets the timer ticks in default configuration to 0. +*/ +void or1k_timer_reset_ticks(void); +/*! +* @} +*/ + +/*! + * \defgroup or1k_multicore Multicore and Synchronization Support + * + * @{ + */ + +/*! + * Compiled with multicore support + * + * \return 1 if compiled with multicore support, 0 otherwise + */ +uint32_t or1k_has_multicore_support(void); + +/*! + * Read core identifier + * + * \return Core identifier + */ +uint32_t or1k_coreid(void); + +/*! + * Read number of cores + * + * \return Total number of cores + */ +uint32_t or1k_numcores(void); + +/*! + * Load linked + * + * Load a value from the given address and link it. If the following + * or1k_sync_sc() goes to the same address and there was no conflicting access + * between loading and storing, the value is written back, else the write fails. + * + * \param address Address to load value from + * \return Value read from the address + */ +uint32_t or1k_sync_ll(void *address); + +/** + * Store conditional + * + * Conditionally store a value to the address. The address must have been read + * before using or1k_sync_ll() and there must be no other load link after that, + * otherwise this will always fail. In case there was no other write to the same + * address in between the load link and the store conditional, the store is + * successful, otherwise it will also fail. + * + * \param address Address to conditionally store to + * \param value Value to write to address + * \return 1 if success, 0 if fail + */ +int or1k_sync_sc(void *address, uint32_t value); + +/*! + * Compare and Swap + * + * Loads a data item from the memory and compares a given value to it. If the + * values match, a new value is written to the memory, if they mismatch, the + * operation is aborted. The whole operation is atomic, i.e., it is guaranteed + * that no other core changes the value between the read and the write. + * + * \param address Address to operate on + * \param compare Compare value + * \param swap New value to write + * \return The value read from memory (can be used to check for success) + */ +uint32_t or1k_sync_cas(void *address, uint32_t compare, uint32_t swap); + +/*! + * Test and Set Lock + * + * Check for a lock on an address. This means, if there is 0 at an address it + * will overwrite it with 1 and return 0. If the lock was already set (value + * 1 read from address), the function returns 1. The operation is atomic. + * + * \param address Address of the lock + * \return 0 if success, 1 if failed + */ +int or1k_sync_tsl(void *address); +/*! + * @} + */ + +#endif /* __NEWLIB_OR1K_SUPPORT_H__ */ |