summaryrefslogtreecommitdiffstats
path: root/libgloss/or1k/include
diff options
context:
space:
mode:
authorJeff Johnston <jjohnstn@redhat.com>2014-12-15 20:17:39 +0000
committerJeff Johnston <jjohnstn@redhat.com>2014-12-15 20:17:39 +0000
commit68a910123726e7868baf89cac9038b4dbb22f612 (patch)
tree108b63e655003a7d58a3cc6f252ab2e6ace706d1 /libgloss/or1k/include
parentd1219c0e89d2dc4ac865889cbd23f5e4c64d86e5 (diff)
downloadcygnal-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.h35
-rw-r--r--libgloss/or1k/include/or1k-support.h665
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__ */