666 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			666 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
| /* 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__ */
 |