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
This commit is contained in:
Jeff Johnston 2014-12-15 20:17:39 +00:00
parent d1219c0e89
commit 68a9101237
21 changed files with 2583 additions and 1 deletions

View File

@ -1,3 +1,26 @@
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
2014-12-15 Stefan Wallentowitz <stefan.wallentowitz@tum.de> 2014-12-15 Stefan Wallentowitz <stefan.wallentowitz@tum.de>
* README: Add details about or1k. * README: Add details about or1k.

View File

@ -55,10 +55,29 @@ OBJCOPY = `if [ -f ${objroot}/../binutils/objcopy ] ; \
then echo ${objroot}/../binutils/objcopy ; \ then echo ${objroot}/../binutils/objcopy ; \
else t='$(program_transform_name)'; echo objcopy | sed -e $$t ; fi` else t='$(program_transform_name)'; echo objcopy | sed -e $$t ; fi`
# object files needed
COMMON_FILES = syscalls \
or1k_uart \
outbyte \
caches-asm \
exceptions \
exceptions-asm \
interrupts \
interrupts-asm \
mmu-asm \
timer \
sbrk \
impure \
util \
sync-asm
LIBOR1K_FILES = $(COMMON_FILES)
LIBOR1K_OBJS = $(addsuffix .o,$(LIBOR1K_FILES))
GCC_LDFLAGS = `if [ -d ${objroot}/../gcc ] ; \ GCC_LDFLAGS = `if [ -d ${objroot}/../gcc ] ; \
then echo -L${objroot}/../gcc ; fi` then echo -L${objroot}/../gcc ; fi`
OUTPUTS = crt0.o OUTPUTS = libor1k.a crt0.o
# Host specific makefile fragment comes in here. # Host specific makefile fragment comes in here.
@host_makefile_frag@ @host_makefile_frag@
@ -70,6 +89,10 @@ all: ${OUTPUTS}
# here's where we build the library for each target # here's where we build the library for each target
# #
libor1k.a: $(LIBOR1K_OBJS)
${AR} ${ARFLAGS} $@ $(LIBOR1K_OBJS)
${RANLIB} $@
doc: doc:
clean mostlyclean: clean mostlyclean:

77
libgloss/or1k/README Normal file
View File

@ -0,0 +1,77 @@
This document describes the internals of the port for OpenRISC
1000. The API is documented in or1k-support.h as Doxygen comments.
# Data Structures
+----------------+ 0x0
| vectors |
+----------------+
| text,data,.. |
+----------------+
| bss |
+----------------+
| heap |
| vv |
| |
| ^^ |
| stack(s) |
+----------------+ _or1k_board_mem_base +
_or1k_board_mem_size
## Stack and Heap
The stack is allocated at the end of available physical memory which
is defined by each board as _or1k_board_mem_base and
_or1k_board_mem_size. The _or1k_stack_top and _or1k_stack_bottom are
determined by those variables and _or1k_stack_size (which may be
overwritten in _or1k_board_init_early).
A second stack for exceptions is allocated as we allow exceptions to
be arbitrary complex and call C functions etc. It is not an option to
re-use the current software stack as we want to be so generic, that
this can also be a virtual memory stack at moment of exception. The
exception starts below the normal software stack and is
_or1k_exception_stack_size large.
Multicore: For each core a stack and exception stack is allocated and
the stack pointer set at boot. That is: sp(core0) = _or1k_stack_top,
sp(core1) = _or1k_stack_top - _or1k_stack_size, etc.
## _or1k_stack_core (multicore only)
An array of pointers to the software stacks (size:
4*or1k_numcores()). It is dynamically allocated from heap in or1k_init
by calling sbrk(). The pointers contain the values for stack top
pointers as described above. This variable is essentially used on boot
of the slave cores to configure the stack register.
## _or1k_exception_stack_core (multicore only)
An array of pointers to the exception stacks (size:
4*or1k_numcores()). It is allocated identical as the stack_core
array. It is loaded whenever an exception occurs to start with a clean
stack in the exception.
## _or1k_exception_handler_table
A table of function pointers to the handlers of the exceptions. The
generic exception handler checks if an exception handler is registered
and calls it. There are 30 exceptions defined (0x0 is not an exception
vector and 0x100 is reset which is static). This array resides in BSS
and is therefore initialized as 0 (no handler registered) after start.
Multicore: As the number of course is not known at compile time, the
variable is a pointer to and array of arrays (cores x 30) which is
allocated in or1k_init() on heap (using sbrk).
## _or1k_interrupt_handler_table and _or1k_interrupt_handler_table_data_ptr
The interrupt handlers are stored identical to to the exception handler table.
## _or1k_reent
The struct _or1k_reent contains formerly global data and allows for
reentrancy. In the single core case, this is an allocated object,
while it is a pointer to an array of structs in the multicore library.
It is allocated in _or1k_reent_init() on the heap.

233
libgloss/or1k/caches-asm.S Normal file
View File

@ -0,0 +1,233 @@
/* caches-asm.S -- cache manipulation for OpenRISC 1000.
*
* Copyright (c) 2011, 2014 Authors
*
* Contributor Julius Baxter <juliusbaxter@gmail.com>
* 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.
*/
#include "include/or1k-asm.h"
#include "include/or1k-sprs.h"
/* -------------------------------------------------------------------------- */
/*!Function used at reset to clear and enable all caches
*/
/* -------------------------------------------------------------------------- */
.global _or1k_cache_init
.type _or1k_cache_init,@function
_or1k_cache_init:
/* Instruction cache enable */
/* Check if IC present and skip enabling otherwise */
l.mfspr r3,r0,OR1K_SPR_SYS_UPR_ADDR
l.andi r4,r3,OR1K_SPR_SYS_UPR_ICP_MASK
l.sfeq r4,r0
OR1K_DELAYED_NOP(OR1K_INST(l.bf .Lnoic))
/* Disable IC */
l.mfspr r6,r0,OR1K_SPR_SYS_SR_ADDR
l.addi r5,r0,-1
l.xori r5,r5,OR1K_SPR_SYS_SR_ICE_MASK
l.and r5,r6,r5
l.mtspr r0,r5,OR1K_SPR_SYS_SR_ADDR
/* Establish cache block size
If BS=0, 16;
If BS=1, 32;
r14 contain block size
*/
l.mfspr r3,r0,OR1K_SPR_SYS_ICCFGR_ADDR
l.andi r4,r3,OR1K_SPR_SYS_ICCFGR_CBS_MASK
l.srli r7,r4,7
l.ori r8,r0,16
l.sll r14,r8,r7
/* Establish number of cache sets
r13 contains number of cache sets
r7 contains log(# of cache sets)
*/
l.andi r4,r3,OR1K_SPR_SYS_ICCFGR_NCS_MASK
l.srli r7,r4,3
l.ori r8,r0,1
l.sll r13,r8,r7
/* Invalidate IC */
l.addi r6,r0,0
l.sll r5,r14,r7
.Linvi: l.mtspr r0,r6,OR1K_SPR_ICACHE_ICBIR_ADDR
l.sfne r6,r5
OR1K_DELAYED(
OR1K_INST(l.add r6,r6,r14),
OR1K_INST(l.bf .Linvi)
)
/* Enable IC */
l.mfspr r6,r0,OR1K_SPR_SYS_SR_ADDR
l.ori r6,r6,OR1K_SPR_SYS_SR_ICE_MASK
l.mtspr r0,r6,OR1K_SPR_SYS_SR_ADDR
l.nop
l.nop
l.nop
l.nop
l.nop
l.nop
l.nop
l.nop
/* Data cache enable */
/* Check if DC present and skip enabling otherwise */
.Lnoic: l.mfspr r3,r0,OR1K_SPR_SYS_UPR_ADDR
l.andi r4,r3,OR1K_SPR_SYS_UPR_DCP_MASK
l.sfeq r4,r0
OR1K_DELAYED_NOP(OR1K_INST(l.bf .Lnodc))
/* Disable DC */
l.mfspr r6,r0,OR1K_SPR_SYS_SR_ADDR
l.addi r5,r0,-1
l.xori r5,r5,OR1K_SPR_SYS_SR_DCE_MASK
l.and r5,r6,r5
l.mtspr r0,r5,OR1K_SPR_SYS_SR_ADDR
/* Establish cache block size
If BS=0, 16;
If BS=1, 32;
r14 contain block size */
l.mfspr r3,r0,OR1K_SPR_SYS_DCCFGR_ADDR
l.andi r4,r3,OR1K_SPR_SYS_DCCFGR_CBS_MASK
l.srli r7,r4,7
l.ori r8,r0,16
l.sll r14,r8,r7
/* Establish number of cache sets
r13 contains number of cache sets
r7 contains log(# of cache sets) */
l.andi r4,r3,OR1K_SPR_SYS_ICCFGR_NCS_MASK
l.srli r7,r4,3
l.ori r8,r0,1
l.sll r13,r8,r7
/* Invalidate DC */
l.addi r6,r0,0
l.sll r5,r14,r7
.Linvd: l.mtspr r0,r6,OR1K_SPR_DCACHE_DCBIR_ADDR
l.sfne r6,r5
OR1K_DELAYED(
OR1K_INST(l.add r6,r6,r14),
OR1K_INST(l.bf .Linvd)
)
/* Enable DC */
l.mfspr r6,r0,OR1K_SPR_SYS_SR_ADDR
l.ori r6,r6,OR1K_SPR_SYS_SR_DCE_MASK
l.mtspr r0,r6,OR1K_SPR_SYS_SR_ADDR
.Lnodc:
/* Return */
OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
/* -------------------------------------------------------------------------- */
/*!Function to enable instruction cache
*/
/* -------------------------------------------------------------------------- */
.global or1k_icache_enable
.type or1k_icache_enable,@function
or1k_icache_enable:
/* Enable IC */
l.mfspr r13,r0,OR1K_SPR_SYS_SR_ADDR
l.ori r13,r13,OR1K_SPR_SYS_SR_ICE_MASK
l.mtspr r0,r13,OR1K_SPR_SYS_SR_ADDR
l.nop
l.nop
l.nop
l.nop
l.nop
OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
/* -------------------------------------------------------------------------- */
/*!Function to disable instruction cache
*/
/* -------------------------------------------------------------------------- */
.global or1k_icache_disable
.type or1k_icache_disable,@function
or1k_icache_disable:
/* Disable IC */
l.mfspr r13,r0,OR1K_SPR_SYS_SR_ADDR
l.addi r12,r0,-1
l.xori r12,r12,OR1K_SPR_SYS_SR_ICE_MASK
l.and r12,r13,r12
l.mtspr r0,r12,OR1K_SPR_SYS_SR_ADDR
OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
/* -------------------------------------------------------------------------- */
/*!Function to flush address of instruction cache
*/
/* -------------------------------------------------------------------------- */
.global or1k_icache_flush
.type or1k_icache_flush,@function
or1k_icache_flush:
OR1K_DELAYED(
OR1K_INST(l.mtspr r0,r3,OR1K_SPR_ICACHE_ICBIR_ADDR),
/* Push r3 into IC invalidate reg */
OR1K_INST(l.jr r9)
)
/* -------------------------------------------------------------------------- */
/*!Function to enable data cache
*/
/* -------------------------------------------------------------------------- */
.global or1k_dcache_enable
.type or1k_dcache_enable,@function
or1k_dcache_enable:
/* Enable DC */
l.mfspr r13,r0,OR1K_SPR_SYS_SR_ADDR
l.ori r13,r13,OR1K_SPR_SYS_SR_DCE_MASK
l.mtspr r0,r13,OR1K_SPR_SYS_SR_ADDR
l.nop
l.nop
l.nop
l.nop
l.nop
OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
/* -------------------------------------------------------------------------- */
/*!Function to disable data cache
*/
/* -------------------------------------------------------------------------- */
.global or1k_dcache_disable
.type or1k_dcache_disable,@function
or1k_dcache_disable:
/* Disable DC */
l.mfspr r13,r0,OR1K_SPR_SYS_SR_ADDR
l.addi r12,r0,-1
l.xori r12,r12,OR1K_SPR_SYS_SR_DCE_MASK
l.and r12,r13,r12
l.mtspr r0,r12,OR1K_SPR_SYS_SR_ADDR
OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
/* -------------------------------------------------------------------------- */
/*!Function to flush address of data cache
*/
/* -------------------------------------------------------------------------- */
.global or1k_dcache_flush
.type or1k_dcache_flush,@function
or1k_dcache_flush:
OR1K_DELAYED(
OR1K_INST(l.mtspr r0,r3,OR1K_SPR_DCACHE_DCBIR_ADDR),
/* Push r3 into DC invalidate reg */
OR1K_INST(l.jr r9)
)

View File

@ -0,0 +1,201 @@
/* exceptions-asm.S -- exception handling for OpenRISC 1000.
*
* Copyright (c) 2011, 2014 Authors
*
* Contributor Julius Baxter <juliusbaxter@gmail.com>
* 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.
*/
#include "include/or1k-asm.h"
#include "include/or1k-sprs.h"
/* -------------------------------------------------------------------------- */
/*!Generic exception handler function
*/
/* -------------------------------------------------------------------------- */
// Warning - this must be the same as specified in crt0.S
#define EXCEPTION_STACK_SIZE 128+128
.extern _or1k_exception_handler_table
/* -------------------------------------------------------------------------- */
/*!Function to call appropriate exception handler
*/
/* -------------------------------------------------------------------------- */
.section .text
.global _or1k_exception_handler
.type _or1k_exception_handler,@function
/*
r3 = address of exception vector
r4 = address where exception occurred
*/
#define GPR_BUF_OFFSET(x) (x << 2)
_or1k_exception_handler:
/* Store remainder of state (r3,r4 stored in vector entry)*/
l.sw GPR_BUF_OFFSET(2)(r1),r2
l.sw GPR_BUF_OFFSET(5)(r1),r5
l.sw GPR_BUF_OFFSET(6)(r1),r6
l.sw GPR_BUF_OFFSET(7)(r1),r7
l.sw GPR_BUF_OFFSET(8)(r1),r8
l.sw GPR_BUF_OFFSET(9)(r1),r9
l.sw GPR_BUF_OFFSET(10)(r1),r10
l.sw GPR_BUF_OFFSET(11)(r1),r11
l.sw GPR_BUF_OFFSET(12)(r1),r12
l.sw GPR_BUF_OFFSET(13)(r1),r13
l.sw GPR_BUF_OFFSET(14)(r1),r14
l.sw GPR_BUF_OFFSET(15)(r1),r15
l.sw GPR_BUF_OFFSET(16)(r1),r16
l.sw GPR_BUF_OFFSET(17)(r1),r17
l.sw GPR_BUF_OFFSET(18)(r1),r18
l.sw GPR_BUF_OFFSET(19)(r1),r19
l.sw GPR_BUF_OFFSET(20)(r1),r20
l.sw GPR_BUF_OFFSET(21)(r1),r21
l.sw GPR_BUF_OFFSET(22)(r1),r22
l.sw GPR_BUF_OFFSET(23)(r1),r23
l.sw GPR_BUF_OFFSET(24)(r1),r24
l.sw GPR_BUF_OFFSET(25)(r1),r25
l.sw GPR_BUF_OFFSET(26)(r1),r26
l.sw GPR_BUF_OFFSET(27)(r1),r27
l.sw GPR_BUF_OFFSET(28)(r1),r28
l.sw GPR_BUF_OFFSET(29)(r1),r29
l.sw GPR_BUF_OFFSET(30)(r1),r30
l.sw GPR_BUF_OFFSET(31)(r1),r31
/* Replace impure pointer for exception */
l.movhi r20,hi(_or1k_exception_impure_ptr)
l.ori r20,r20,lo(_or1k_exception_impure_ptr)
#ifdef __OR1K_MULTICORE__
l.lwz r20,0(r20)
l.mfspr r22,r0,OR1K_SPR_SYS_COREID_ADDR
l.slli r22,r22,2
l.add r20,r20,r22
#endif
l.lwz r20,0(r20)
l.movhi r21,hi(_or1k_current_impure_ptr)
l.ori r21,r21,lo(_or1k_current_impure_ptr)
#ifdef __OR1K_MULTICORE__
l.lwz r21,0(r21)
l.add r21,r21,r22
#endif
l.sw 0(r21),r20
/* Determine offset in table of exception handler using r3*/
l.andi r13,r3,0xff00
l.srli r13,r13,6
/* Substract 2 words, as we have no vector at 0 and no reset handler */
l.addi r13,r13,-8
/* r13 now contains offset in or1k_exception_handler_table for
function
*/
/* Get or1k_exception_handler_table address */
l.movhi r14,hi(_or1k_exception_handler_table)
l.ori r14,r14,lo(_or1k_exception_handler_table)
#ifdef __OR1K_MULTICORE__
/* Read the address of the array of cores */
/* r14 = (*or1k_exception_handler_table) */
l.lwz r14,0(r14)
/* Generate core offset in array (off = coreid*30*4 = coreid*120) */
/* r15 = coreid */
l.mfspr r15,r0,OR1K_SPR_SYS_COREID_ADDR
/* r16 = coreid * 128 */
l.slli r16,r15,7
/* r15 = coreid * 8 */
l.slli r15,r15,3
/* r15 = coreid*128 - coreid*8 = coreid*120 = off */
l.sub r15,r16,r15
/* r14 = (*or1k_exception_handler_table)[coreid] = r14 + off */
l.add r14,r14,r15
#endif
/* r14 now contains base of exception handler table */
/* add offset of exception vector */
l.add r14,r14,r13
/* load handler address from table */
l.lwz r13, 0(r14)
/* Check to see if this handler has been set yet */
l.sfne r13,r0
OR1K_DELAYED_NOP(OR1K_INST(l.bnf exception_exit))
/* Call exception handler, copy EPCR to r3 */
OR1K_DELAYED(
OR1K_INST(l.or r3,r4,r4),
OR1K_INST(l.jalr r13)
)
/* Restore impure pointer */
l.movhi r20,hi(_or1k_impure_ptr)
l.ori r20,r20,lo(_or1k_impure_ptr)
#ifdef __OR1K_MULTICORE__
l.lwz r20,0(r20)
l.mfspr r22,r0,OR1K_SPR_SYS_COREID_ADDR
l.slli r22,r22,2
l.add r20,r20,r22
#endif
l.lwz r20,0(r20)
l.movhi r21,hi(_or1k_current_impure_ptr)
l.ori r21,r21,lo(_or1k_current_impure_ptr)
#ifdef __OR1K_MULTICORE__
l.lwz r21,0(r21)
l.add r21,r21,r22
#endif
l.sw 0(r21),r20
/* Restore state */
l.lwz r2,GPR_BUF_OFFSET(2)(r1)
l.lwz r3,GPR_BUF_OFFSET(3)(r1)
l.lwz r4,GPR_BUF_OFFSET(4)(r1)
l.lwz r5,GPR_BUF_OFFSET(5)(r1)
l.lwz r6,GPR_BUF_OFFSET(6)(r1)
l.lwz r7,GPR_BUF_OFFSET(7)(r1)
l.lwz r8,GPR_BUF_OFFSET(8)(r1)
l.lwz r9,GPR_BUF_OFFSET(9)(r1)
l.lwz r10,GPR_BUF_OFFSET(10)(r1)
l.lwz r11,GPR_BUF_OFFSET(11)(r1)
l.lwz r12,GPR_BUF_OFFSET(12)(r1)
l.lwz r13,GPR_BUF_OFFSET(13)(r1)
l.lwz r14,GPR_BUF_OFFSET(14)(r1)
l.lwz r15,GPR_BUF_OFFSET(15)(r1)
l.lwz r16,GPR_BUF_OFFSET(16)(r1)
l.lwz r17,GPR_BUF_OFFSET(17)(r1)
l.lwz r18,GPR_BUF_OFFSET(18)(r1)
l.lwz r19,GPR_BUF_OFFSET(19)(r1)
l.lwz r20,GPR_BUF_OFFSET(20)(r1)
l.lwz r21,GPR_BUF_OFFSET(21)(r1)
l.lwz r22,GPR_BUF_OFFSET(22)(r1)
l.lwz r23,GPR_BUF_OFFSET(23)(r1)
l.lwz r24,GPR_BUF_OFFSET(24)(r1)
l.lwz r25,GPR_BUF_OFFSET(25)(r1)
l.lwz r26,GPR_BUF_OFFSET(26)(r1)
l.lwz r27,GPR_BUF_OFFSET(27)(r1)
l.lwz r28,GPR_BUF_OFFSET(28)(r1)
l.lwz r29,GPR_BUF_OFFSET(29)(r1)
l.lwz r30,GPR_BUF_OFFSET(30)(r1)
l.lwz r31,GPR_BUF_OFFSET(31)(r1)
// Restore original stack
l.lwz r1,GPR_BUF_OFFSET(1)(r1)
l.rfe
l.nop
exception_exit:
/* Exception handler not set, exit */
OR1K_DELAYED(
OR1K_INST(l.or r3,r4,r4),
OR1K_INST(l.jal exit)
)

View File

@ -0,0 +1,21 @@
#include "include/or1k-support.h"
#include "or1k-internals.h"
#ifdef __OR1K_MULTICORE__
or1k_exception_handler_table_t *_or1k_exception_handler_table;
#else
or1k_exception_handler_table_t _or1k_exception_handler_table;
#endif
void or1k_exception_handler_add(int id, or1k_exception_handler_fptr handler)
{
// Subtract 2 as we do not have a vector at 0 and reset is static
id = id - 2;
#ifdef __OR1K_MULTICORE__
_or1k_exception_handler_table[or1k_coreid()][id] = handler;
#else
_or1k_exception_handler_table[id] = handler;
#endif
}

120
libgloss/or1k/impure.c Normal file
View File

@ -0,0 +1,120 @@
/* impure.c. Handling of re-entrancy data structure for OpenRISC 1000.
Copyright (C) 2014, Authors
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.
*/
#include <reent.h>
#include "or1k-internals.h"
#include <string.h>
/* As an exception handler may also use the library, it is better to use
* a different re-entrancy data structure for the exceptions.
* This data structure is configured here and as part of the exception
* handler (or1k_exception_handler) temporarily replaces the software's
* impure data pointer.
*
* During initialization, the libraries standard _impure_data and the exception
* impure data (_exception_impure_data) are initialized. Afterwards,
* the current value _current_impure_ptr is set to _impure_ptr.
*
* At runtime __getreent is called to return the current reentrancy pointer,
* which is stored in _current_impure_ptr.
*
* In the or1k_exception_handler the _current_impure_ptr is set to point to
* _exception_impure_ptr. After the exception handler returned, it is set back
* to _impure_ptr.
*/
/* Link in the external impure_data structure */
extern struct _reent *__ATTRIBUTE_IMPURE_PTR__ _impure_ptr;
#ifdef __OR1K_MULTICORE__
struct _reent **_or1k_impure_ptr;
struct _reent **_or1k_exception_impure_ptr;
struct _reent **_or1k_current_impure_ptr;
#else
struct _reent *__ATTRIBUTE_IMPURE_PTR__ _or1k_impure_ptr;
/* Create exception impure data structure */
static struct _reent _or1k_exception_impure_data = _REENT_INIT (_or1k_exception_impure_data);
/* Link to the exception impure data structure */
struct _reent *__ATTRIBUTE_IMPURE_PTR__ _or1k_exception_impure_ptr = &_or1k_exception_impure_data;
/* Link to the currently used data structure. */
struct _reent *__ATTRIBUTE_IMPURE_PTR__ _or1k_current_impure_ptr;
#endif
#ifdef __OR1K_MULTICORE__
#define OR1K_LIBC_GETREENT _or1k_current_impure_ptr[or1k_coreid()]
#else
#define OR1K_LIBC_GETREENT _or1k_current_impure_ptr
#endif
void
_or1k_libc_impure_init (void)
{
#ifdef __OR1K_MULTICORE__
uint32_t c;
_or1k_impure_ptr = _sbrk_r(0, sizeof(struct _reent*) * or1k_numcores());
_or1k_exception_impure_ptr = _sbrk_r(0, sizeof(struct _reent*) * or1k_numcores());
_or1k_current_impure_ptr = _sbrk_r(0, sizeof(struct _reent*) * or1k_numcores());
_or1k_impure_ptr[0] = _impure_ptr;
_REENT_INIT_PTR(_impure_ptr);
for (c = 1; c < or1k_numcores(); c++) {
_or1k_impure_ptr[c] = _sbrk_r(0, sizeof(struct _reent));
_REENT_INIT_PTR(_or1k_impure_ptr[c]);
}
for (c = 0; c < or1k_numcores(); c++) {
_or1k_exception_impure_ptr[c] = _sbrk_r(0, sizeof(struct _reent));
_REENT_INIT_PTR(_or1k_exception_impure_ptr[c]);
}
for (c = 0; c < or1k_numcores(); c++) {
_or1k_current_impure_ptr[c] = _or1k_impure_ptr[c];
}
#else
// Initialize both impure data structures
_REENT_INIT_PTR (_impure_ptr);
_REENT_INIT_PTR (_or1k_exception_impure_ptr);
// Set current to standard impure pointer
_or1k_current_impure_ptr = _impure_ptr;
#endif
}
struct _reent*
_or1k_libc_getreent(void) {
return OR1K_LIBC_GETREENT;
}
#ifdef __OR1K_MULTICORE__
struct _or1k_reent (*_or1k_reent)[];
#else
struct _or1k_reent _or1k_reent;
#endif
void
_or1k_reent_init(void)
{
#ifdef __OR1K_MULTICORE__
size_t memsize = sizeof(struct _or1k_reent) * or1k_numcores();
_or1k_reent = (struct _or1k_reent*) _sbrk_r(0, memsize);
#endif
}

View File

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

View File

@ -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__ */

View File

@ -0,0 +1,166 @@
/* interrupts-asm.S -- interrupt handling for OpenRISC 1000.
*
* Copyright (c) 2011, 2012, 2014 Authors
*
* Contributor Julius Baxter <juliusbaxter@gmail.com>
* Contributor Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
* 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.
*/
/* -------------------------------------------------------------------------- */
/*!Generic interrupt handler function for or1k
*/
/* -------------------------------------------------------------------------- */
#include "include/or1k-asm.h"
#include "include/or1k-sprs.h"
.extern _or1k_interrupt_handler_table
.extern _or1k_interrupt_handler_data_ptr_table
/* -------------------------------------------------------------------------- */
/*!Function to call appropriate interrupt handler
*/
/* -------------------------------------------------------------------------- */
.section .text
.global _or1k_interrupt_handler
.type _or1k_interrupt_handler,@function
_or1k_interrupt_handler:
/* Make room on stack, save link register */
l.addi r1,r1,-12
l.sw 0(r1),r9
/* Read PICSR */
l.mfspr r3,r0,OR1K_SPR_PIC_PICSR_ADDR
/* Load handler table base address */
l.movhi r7,hi(_or1k_interrupt_handler_table)
l.ori r7,r7,lo(_or1k_interrupt_handler_table)
/* Load data pointer table base address */
l.movhi r12,hi(_or1k_interrupt_handler_data_ptr_table)
l.ori r12,r12,lo(_or1k_interrupt_handler_data_ptr_table)
#ifdef __OR1K_MULTICORE__
/* Read the addresses of the arrays of cores */
/* r7 = (*or1k_interrupt_handler_table) */
l.lwz r7,0(r7)
/* r12 = (*or1k_interrupt_handler_data_ptr_table) */
l.lwz r12,0(r12)
/* Generate offset in arrays */
/* r14 = coreid */
l.mfspr r14,r0,OR1K_SPR_SYS_COREID_ADDR
/* r14 = coreid*32*4 = off */
l.slli r14,r14,7
/* r7 = (*or1k_exception_handler_table)[coreid] */
l.add r7,r7,r14
/* r12 = (*or1k_exception_handler_table)[coreid] */
l.add r12,r12,r14
#endif
.L0:
/* Find first set bit in PICSR */
l.ff1 r4,r3
/* Any bits set? */
l.sfne r4,r0
/* If none, finish */
OR1K_DELAYED_NOP(OR1K_INST(l.bnf .L2))
/* What is IRQ function table offset? */
l.addi r5,r4,-1
l.slli r6,r5,2
/* Add this to table bases */
l.add r14,r6,r7
l.add r13,r6,r12
/* Fetch handler function address */
l.lwz r14,0(r14)
/* Double check it's valid, compare against INTERRUPT_HANDLER_NOT_SET */
l.sfne r14,r0
/* Skip if no handler: TODO: Indicate interrupt fired but no handler*/
OR1K_DELAYED_NOP(OR1K_INST(l.bnf .L1))
/* Pull out data pointer from table, save r3, we'll write over it */
l.sw 4(r1),r3
l.lwz r3,0(r13)
/* Call handler, save r5 in delay slot */
OR1K_DELAYED(
OR1K_INST(l.sw 8(r1),r5),
OR1K_INST(l.jalr r14)
)
/* Reload r3,r5 */
l.lwz r3,4(r1)
l.lwz r5,8(r1)
.L1:
/* Clear bit from PICSR, return to start of checking loop */
l.ori r6,r0,1
l.sll r6,r6,r5
OR1K_DELAYED(
OR1K_INST(l.xor r3,r3,r6),
OR1K_INST(l.j .L0)
)
.L2:
/* Finish up - write PICSR back, restore r9*/
l.lwz r9,0(r1)
l.mtspr r0,r3,OR1K_SPR_PIC_PICSR_ADDR
OR1K_DELAYED(
OR1K_INST(l.addi r1,r1,12),
OR1K_INST(l.jr r9)
)
/* -------------------------------------------------------------------------- */
/*!Function to enable an interrupt handler in the PICMR
*/
/* -------------------------------------------------------------------------- */
.global or1k_interrupt_enable
.type or1k_interrupt_enable,@function
/* r3 should have IRQ line for peripheral */
or1k_interrupt_enable:
l.addi r1,r1,-4
l.sw 0(r1),r4
l.ori r4,r0,0x1
l.sll r4,r4,r3
l.mfspr r3,r0,OR1K_SPR_PIC_PICMR_ADDR
l.or r3,r3,r4
l.mtspr r0,r3,OR1K_SPR_PIC_PICMR_ADDR
l.lwz r4,0(r1)
OR1K_DELAYED(
OR1K_INST(l.addi r1,r1,4),
OR1K_INST(l.jr r9)
)
/* -------------------------------------------------------------------------- */
/*!Function to disable an interrupt handler in the PICMR
*/
/* -------------------------------------------------------------------------- */
.global or1k_interrupt_disable
.type or1k_interrupt_disable,@function
/* r3 should have IRQ line for peripheral */
or1k_interrupt_disable:
l.addi r1,r1,-4
l.sw 0(r1),r4
l.ori r4,r0,0x1
l.sll r4,r4,r3
l.xori r4,r4,0xffff
l.mfspr r3,r0,OR1K_SPR_PIC_PICMR_ADDR
l.and r3,r3,r4
l.mtspr r0,r3,OR1K_SPR_PIC_PICMR_ADDR
l.lwz r4,0(r1)
OR1K_DELAYED(
OR1K_INST(l.addi r1,r1,4),
OR1K_INST(l.jr r9)
)

View File

@ -0,0 +1,69 @@
/* interrupts.c -- interrupt handling for OpenRISC 1000.
*
* Copyright (c) 2014 Authors
*
* 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.
*/
#include "include/or1k-support.h"
#include "include/or1k-sprs.h"
#include <stdint.h>
#include "or1k-internals.h"
#ifdef __OR1K_MULTICORE__
or1k_interrupt_handler_table_t *_or1k_interrupt_handler_table;
or1k_interrupt_handler_data_ptr_table_t *_or1k_interrupt_handler_data_ptr_table;
#else
or1k_interrupt_handler_table_t _or1k_interrupt_handler_table;
or1k_interrupt_handler_data_ptr_table_t _or1k_interrupt_handler_data_ptr_table;
#endif
void or1k_interrupt_handler_add(uint32_t id,
or1k_interrupt_handler_fptr handler,
void *data_ptr)
{
#ifdef __OR1K_MULTICORE__
_or1k_interrupt_handler_table[or1k_coreid()][id] = handler;
_or1k_interrupt_handler_data_ptr_table[or1k_coreid()][id] = (uint32_t) data_ptr;
#else
_or1k_interrupt_handler_table[id] = handler;
_or1k_interrupt_handler_data_ptr_table[id] = (uint32_t) data_ptr;
#endif
}
void
or1k_interrupts_enable(void)
{
uint32_t sr = or1k_mfspr(OR1K_SPR_SYS_SR_ADDR);
sr = OR1K_SPR_SYS_SR_IEE_SET(sr, 1);
or1k_mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
}
uint32_t
or1k_interrupts_disable(void)
{
uint32_t oldsr, newsr;
oldsr= or1k_mfspr(OR1K_SPR_SYS_SR_ADDR);
newsr = OR1K_SPR_SYS_SR_IEE_SET(oldsr, 0);
or1k_mtspr(OR1K_SPR_SYS_SR_ADDR, newsr);
return OR1K_SPR_SYS_SR_IEE_GET(oldsr);
}
void
or1k_interrupts_restore(uint32_t sr_iee)
{
uint32_t sr = or1k_mfspr(OR1K_SPR_SYS_SR_ADDR);
sr = OR1K_SPR_SYS_SR_IEE_SET(sr, sr_iee);
or1k_mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
}

67
libgloss/or1k/mmu-asm.S Normal file
View File

@ -0,0 +1,67 @@
/* mmu-asm.S -- MMU handling for OpenRISC 1000.
*
* Copyright (c) 2011, 2014 Authors
*
* Contributor Julius Baxter <juliusbaxter@gmail.com>
* 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.
*/
/* -------------------------------------------------------------------------- */
/*!Function to control MMU
*/
/* -------------------------------------------------------------------------- */
#include "include/or1k-asm.h"
#include "include/or1k-sprs.h"
/* MMU control functions always switch MMU control with a l.rfe to return
from function */
.section .text
.global or1k_dmmu_enable
or1k_dmmu_enable:
l.mfspr r3,r0,OR1K_SPR_SYS_SR_ADDR
l.ori r3,r3,OR1K_SPR_SYS_SR_DME_MASK
l.mtspr r0,r3,OR1K_SPR_SYS_ESR_BASE
l.mtspr r0,r9,OR1K_SPR_SYS_EPCR_BASE
OR1K_DELAYED_NOP(OR1K_INST(l.rfe))
.global or1k_dmmu_disable
or1k_dmmu_disable:
l.ori r3,r0,OR1K_SPR_SYS_SR_DME_MASK
l.xori r4,r3,0xffff
l.mfspr r3,r0,OR1K_SPR_SYS_SR_ADDR
l.and r3,r4,r3
l.mtspr r0,r3,OR1K_SPR_SYS_ESR_BASE
l.mtspr r0,r9,OR1K_SPR_SYS_EPCR_BASE
OR1K_DELAYED_NOP(OR1K_INST(l.rfe))
.global or1k_immu_enable
or1k_immu_enable:
l.mfspr r3,r0,OR1K_SPR_SYS_SR_ADDR
l.ori r3,r3,OR1K_SPR_SYS_SR_IME_MASK
l.mtspr r0,r3,OR1K_SPR_SYS_ESR_BASE
l.mtspr r0,r9,OR1K_SPR_SYS_EPCR_BASE
OR1K_DELAYED_NOP(OR1K_INST(l.rfe))
.global or1k_immu_disable
or1k_immu_disable:
l.ori r3,r0,OR1K_SPR_SYS_SR_IME_MASK
l.xori r4,r3,0xffff
l.mfspr r3,r0,OR1K_SPR_SYS_SR_ADDR
l.and r3,r4,r3
l.mtspr r0,r3,OR1K_SPR_SYS_ESR_BASE
l.mtspr r0,r9,OR1K_SPR_SYS_EPCR_BASE
OR1K_DELAYED_NOP(OR1K_INST(l.rfe))

View File

@ -0,0 +1,67 @@
#ifndef __OR1K_INTERNAL_H__
#define __OR1K_INTERNAL_H__
#include <stdint.h>
#include <string.h>
#include "include/or1k-support.h"
extern uint32_t* _or1k_stack_top;
extern size_t _or1k_stack_size;
extern uint32_t* _or1k_stack_bottom;
extern uint32_t* _or1k_exception_stack_top;
extern size_t _or1k_exception_stack_size;
extern uint32_t* _or1k_exception_stack_bottom;
#ifdef __OR1K_MULTICORE__
extern uint32_t* *_or1k_stack_core;
extern uint32_t* *_or1k_exception_stack_core;
#endif
// The first two vectors are not used (address 0 and reset)
#define OR1K_NUM_EXCEPTIONS 30
typedef or1k_exception_handler_fptr or1k_exception_handler_table_t[OR1K_NUM_EXCEPTIONS];
#ifdef __OR1K_MULTICORE__
extern or1k_exception_handler_table_t *_or1k_exception_handler_table;
#else
extern or1k_exception_handler_table_t _or1k_exception_handler_table;
#endif
typedef or1k_interrupt_handler_fptr or1k_interrupt_handler_table_t[32];
typedef void* or1k_interrupt_handler_data_ptr_table_t[32];
#ifdef __OR1K_MULTICORE__
extern or1k_interrupt_handler_table_t *_or1k_interrupt_handler_table;
extern or1k_interrupt_handler_data_ptr_table_t *_or1k_interrupt_handler_data_ptr_table;
#else
extern or1k_interrupt_handler_table_t _or1k_interrupt_handler_table;
extern or1k_interrupt_handler_data_ptr_table_t _or1k_interrupt_handler_data_ptr_table;
#endif
extern void _or1k_interrupt_handler(void);
struct _or1k_reent {
/* Tick timer variable */
volatile uint32_t or1k_timer_ticks;
/* Tick rate storage */
uint32_t or1k_timer_period;
uint32_t or1k_timer_mode;
};
#ifdef __OR1K_MULTICORE__
extern struct _or1k_reent (*_or1k_reent)[];
#define OR1K_REENT (*_or1k_reent)[or1k_coreid()]
#else
extern struct _or1k_reent _or1k_reent;
#define OR1K_REENT _or1k_reent
#endif
extern void _or1k_reent_init();
#endif

82
libgloss/or1k/or1k_uart.c Normal file
View File

@ -0,0 +1,82 @@
/* or1k_uart.c -- UART implementation for OpenRISC 1000.
*
*Copyright (c) 2014 Authors
*
* 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.
*/
#include "include/or1k-support.h"
#include "or1k_uart.h"
#include <stdint.h>
void (*_or1k_uart_read_cb)(char c);
void _or1k_uart_interrupt_handler(uint32_t data)
{
_or1k_uart_read_cb(REG8(RB));
}
int _or1k_uart_init(void)
{
uint16_t divisor;
// Is uart present?
if (!_or1k_board_uart_base) {
return -1;
}
// Reset the callback function
_or1k_uart_read_cb = 0;
// Calculate and set divisor
divisor = _or1k_board_clk_freq / (_or1k_board_uart_baud * 16);
REG8(LCR) = LCR_DLA;
REG8(DLB1) = divisor & 0xff;
REG8(DLB2) = divisor >> 8;
// Set line control register:
// - 8 bits per character
// - 1 stop bit
// - No parity
// - Break disabled
// - Disallow access to divisor latch
REG8(LCR) = LCR_BPC_8;
// Reset FIFOs and set trigger level to 14 bytes
REG8(FCR) = FCR_CLRRECV | FCR_CLRTMIT | FCR_TRIG_14;
// Disable all interrupts
REG8(IER) = 0;
return 0;
}
void _or1k_uart_write(char c)
{
while (!REG8(LSR) & LSR_TFE) {}
REG8(THR) = c;
}
void or1k_uart_set_read_cb(void (*cb)(char c))
{
_or1k_uart_read_cb = cb;
// Enable interrupt
REG8(IER) = 1 << IER_RDAI;
or1k_interrupt_handler_add(_or1k_board_uart_IRQ,
_or1k_uart_interrupt_handler, 0);
or1k_interrupt_enable(_or1k_board_uart_IRQ);
}

83
libgloss/or1k/or1k_uart.h Normal file
View File

@ -0,0 +1,83 @@
/* or1k_uart.h -- UART definitions for OpenRISC 1000.
*
* Copyright (c) 2014 Authors
*
* 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 is the generic board support for the OpenCores UART device */
#include <stdint.h>
#include "board.h"
extern void (*_or1k_uart_read_cb)(char c);
void _or1k_uart_interrupt_handler(uint32_t data);
int _or1k_uart_init(void);
void _or1k_uart_write(char c);
#define RB _or1k_board_uart_base + 0
#define THR _or1k_board_uart_base + 0
#define IER _or1k_board_uart_base + 1
#define IIR _or1k_board_uart_base + 2
#define FCR _or1k_board_uart_base + 2
#define LCR _or1k_board_uart_base + 3
#define MCR _or1k_board_uart_base + 4
#define LSR _or1k_board_uart_base + 5
#define MSR _or1k_board_uart_base + 6
#define DLB1 _or1k_board_uart_base + 0
#define DLB2 _or1k_board_uart_base + 1
#define IER_RDAI 0
#define IER_TEI 1
#define IER_RLSI 2
#define IER_MSI 3
#define IIR_RLS 0xC3
#define IIR_RDA 0xC2
#define IIR_TO 0xC6
#define IIR_THRE 0xC1
#define IIT_MS 0xC0
#define FCR_CLRRECV 0x1
#define FCR_CLRTMIT 0x2
#define FCR_TRIG_1 0x0
#define FCR_TRIG_4 0x40
#define FCR_TRIG_8 0x80
#define FCR_TRIG_14 0xC0
#define LCR_BPC_MASK 0x3
#define LCR_SB_MASK 0x4
#define LCR_BPC_5 0x0
#define LCR_BPC_6 0x1
#define LCR_BPC_7 0x2
#define LCR_BPC_8 0x3
#define LCR_SB_1 0x0
#define LCR_SB_2 0x4
#define LCR_PE 0x8
#define LCR_EPS 0x10
#define LCR_SP 0x20
#define LCR_BC 0x40
#define LCR_DLA 0x80
#define LSR_DR 0x0
#define LSR_OE 0x2
#define LSR_PE 0x4
#define LSR_FE 0x8
#define LSR_BI 0x10
#define LSR_TFE 0x20
#define LSR_TEI 0x40

34
libgloss/or1k/outbyte.S Normal file
View File

@ -0,0 +1,34 @@
/* outbyte.S -- Write one byte for OpenRISC 1000.
*
* Copyright (c) 2014 Authors
*
* 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.
*/
#include "include/or1k-asm.h"
.global _or1k_outbyte
.text
_or1k_outbyte:
LOAD_SYMBOL_2_GPR(r4,_or1k_board_uart_base)
l.lwz r4, 0(r4)
l.sfeq r4, r0
OR1K_DELAYED_NOP(l.bf .Lnouart)
.Luart:
OR1K_DELAYED_NOP(l.j _or1k_uart_write)
.Lnouart:
OR1K_DELAYED(
OR1K_INST(l.nop 0x4),
OR1K_INST(l.jr r9)
)

52
libgloss/or1k/sbrk.c Normal file
View File

@ -0,0 +1,52 @@
/* sbrk.c -- allocate space on heap on OpenRISC 1000.
*
* Copyright (c) 2014 Authors
*
* 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.
*/
#include <reent.h>
#include "include/or1k-support.h"
static uint32_t _or1k_heap_end;
void *
_sbrk_r (struct _reent * reent, ptrdiff_t incr)
{
extern uint32_t end; /* Set by linker. */
uint32_t prev_heap_end;
// This needs to be atomic
// Disable interrupts on this core
uint32_t sr_iee = or1k_interrupts_disable();
uint32_t sr_tee = or1k_timer_disable();
// Initialize heap end to end if not initialized before
or1k_sync_cas((void*) &_or1k_heap_end, 0, (uint32_t) &end);
do {
// Read previous heap end
prev_heap_end = _or1k_heap_end;
// and try to set it to the new value as long as it has changed
} while (or1k_sync_cas((void*) &_or1k_heap_end,
(uint32_t) prev_heap_end,
(uint32_t) (prev_heap_end + incr)) != (uint32_t) prev_heap_end);
// Restore interrupts on this core
or1k_timer_restore(sr_tee);
or1k_interrupts_restore(sr_iee);
return (void*) prev_heap_end;
}

135
libgloss/or1k/sync-asm.S Normal file
View File

@ -0,0 +1,135 @@
#include "include/or1k-asm.h"
#include "include/or1k-sprs.h"
.section .text
.global or1k_has_multicore_support
.type or1k_has_multicore_support,@function
or1k_has_multicore_support:
#ifdef __OR1K_MULTICORE__
// Return 1
OR1K_DELAYED(
OR1K_INST(l.ori r11,r0,1),
OR1K_INST(l.jr r9)
)
#else
// Return 0
OR1K_DELAYED(
OR1K_INST(l.or r11,r0,r0),
OR1K_INST(l.jr r9)
)
#endif
.global or1k_coreid
.type or1k_coreid,@function
or1k_coreid:
#ifdef __OR1K_MULTICORE__
// Return SPR with core identifier
OR1K_DELAYED(
OR1K_INST(l.mfspr r11,r0,OR1K_SPR_SYS_COREID_ADDR),
OR1K_INST(l.jr r9)
)
#else
// Return 0
OR1K_DELAYED(
OR1K_INST(l.or r11,r0,r0),
OR1K_INST(l.jr r9)
)
#endif
.global or1k_numcores
.type or1k_numcores,@function
or1k_numcores:
#ifdef __OR1K_MULTICORE__
// Return SPR with number of cores
OR1K_DELAYED(
OR1K_INST(l.mfspr r11,r0,OR1K_SPR_SYS_NUMCORES_ADDR),
OR1K_INST(l.jr r9)
)
#else
// Return 1
OR1K_DELAYED(
OR1K_INST(l.ori r11,r0,1),
OR1K_INST(l.jr r9)
)
#endif
.global or1k_sync_ll
.type or1k_sync_ll,@function
or1k_sync_ll:
#ifdef __OR1K_MULTICORE__
// Load word atomic
OR1K_DELAYED(
OR1K_INST(l.lwa r11, 0(r3)),
OR1K_INST(l.jr r9)
)
#else
// Simply load word, TODO: throw exception? which?
OR1K_DELAYED(
OR1K_INST(l.lwz r11, 0(r3)),
OR1K_INST(l.jr r9)
)
#endif
.global or1k_sync_sc
.type or1k_sync_sc,@function
or1k_sync_sc:
#ifdef __OR1K_MULTICORE__
// swa sets the flag if it was succesfull
// Store the value to address and set flag
l.swa 0(r3),r4
OR1K_DELAYED(
// Set return to success speculatively (may go to delay slot)
OR1K_INST(l.ori r11,r0,1),
// If the swa was successfull, jump to end
OR1K_INST(l.bf .or1k_sync_sc_done)
)
// If the swa was not successfull, set
l.or r11,r0,r0
.or1k_sync_sc_done:
OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
#else
// Simply store word, TODO: throw exception? which?
OR1K_DELAYED(
OR1K_INST(l.sw 0(r3),r4),
OR1K_INST(l.jr r9)
)
#endif
.global or1k_sync_cas
.type or1k_sync_sc,@function
or1k_sync_cas:
#ifdef __OR1K_MULTICORE__
/* Load linked address value to return register */
l.lwa r11,0(r3)
/* Compare value to parameter */
l.sfeq r11,r4
/* If not equal: abort and return the read value */
OR1K_DELAYED_NOP(OR1K_INST(l.bnf .or1k_sync_cas_done))
/* If compare was successfull: try writing */
l.swa 0(r3),r5
/* If writing was not successful: restart */
OR1K_DELAYED_NOP(OR1K_INST(l.bnf or1k_sync_cas))
.or1k_sync_cas_done:
/* Return value is the original read value */
OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
#else
// Non-atomic CAS, TODO: throw exception? which?
l.lwz r11,0(r3)
l.sfeq r11,r4
OR1K_DELAYED_NOP(OR1K_INST(l.bnf .or1k_sync_cas_done))
l.sw 0(r3),r5
.or1k_sync_cas_done:
OR1K_DELAYED_NOP(OR1K_INST(l.jr r9))
#endif
.global or1k_sync_tsl
.type or1k_sync_tsl,@function
or1k_sync_tsl:
l.or r4,r0,r0
OR1K_DELAYED(
OR1K_INST(l.addi r5,r0,1),
OR1K_INST(l.j or1k_sync_cas)
)

160
libgloss/or1k/syscalls.c Normal file
View File

@ -0,0 +1,160 @@
/* syscalls.c -- reentrant syscalls for OpenRISC 1000.
*
* Copyright (c) 2011, 2014 Authors
*
* Contributor Julius Baxter <juliusbaxter@gmail.com>
* 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.
*/
#include <errno.h>
#include <reent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include "board.h"
/* Write is actually the only thing we provide. All other are stubs.. */
extern void _or1k_outbyte(char c);
_ssize_t
_write_r(struct _reent * reent, int fd, const void *buf, size_t nbytes)
{
int i;
char* b = (char*) buf;
for (i = 0; i < nbytes; i++) {
if (*(b + i) == '\n') {
_or1k_outbyte ('\r');
}
_or1k_outbyte (*(b + i));
}
return (nbytes);
}
void
_exit(int rc)
{
_or1k_board_exit();
while (1) {}
}
int
_close_r(struct _reent *reent, int fildes)
{
reent->_errno = ENOSYS;
return -1;
}
char *__env[1] = { 0 };
char **environ = __env;
int
_execve_r(struct _reent *reent, const char *name, char * const *argv,
char * const *env)
{
reent->_errno = ENOSYS;
return -1;
}
int
_fork_r(struct _reent *reent)
{
errno = ENOSYS;
return -1;
}
int
_fstat_r(struct _reent *reent, int fildes, struct stat *st)
{
reent->_errno = ENOSYS;
return -1;
}
int
_getpid_r(struct _reent *reent)
{
reent->_errno = ENOSYS;
return -1;
}
int
_gettimeofday(struct _reent *reent, struct timeval *ptimeval, void *ptimezone)
{
reent->_errno = ENOSYS;
return -1;
}
int
_isatty_r(struct _reent *reent, int file)
{
reent->_errno = ENOSYS;
return 0;
}
int
_kill_r(struct _reent *reent, int pid, int sig)
{
reent->_errno = ENOSYS;
return -1;
}
int
_link_r(struct _reent *reent, const char *existing, const char *new)
{
reent->_errno = ENOSYS;
return -1;
}
_off_t
_lseek_r(struct _reent *reent, int file, _off_t ptr, int dir)
{
errno = ENOSYS;
return -1;
}
int
_open(struct _reent *reent, char *file, int flags, int mode)
{
reent->_errno = ENOSYS;
return -1;
}
_ssize_t
_read_r(struct _reent *reent, int file, void *ptr, size_t len)
{
reent->_errno = ENOSYS;
return -1;
}
int
_readlink_r(struct _reent *reent, const char *path, char *buf, size_t bufsize)
{
reent->_errno = ENOSYS;
return -1;
}
int
_stat_r(struct _reent *reent, const char *path, struct stat *buf)
{
reent->_errno = EIO;
return -1;
}
int
_unlink_r(struct _reent *reent, const char * path)
{
reent->_errno = EIO;
return (-1);
}

186
libgloss/or1k/timer.c Normal file
View File

@ -0,0 +1,186 @@
/* timer.c -- tick timer functions for OpenRISC 1000.
*
* Copyright (c) 2011, 2014 Authors
*
* Contributor Julius Baxter <juliusbaxter@gmail.com>
* 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.
*/
#include "include/or1k-support.h"
#include "include/or1k-sprs.h"
#include "or1k-internals.h"
#include "board.h"
/* --------------------------------------------------------------------------*/
/*!Tick timer interrupt handler
Increment timer ticks counter, reload TTMR
*/
/* --------------------------------------------------------------------------*/
void
_or1k_timer_interrupt_handler(void)
{
OR1K_REENT.or1k_timer_ticks++;
uint32_t ttmr = or1k_mfspr(OR1K_SPR_TICK_TTMR_ADDR);
ttmr = OR1K_SPR_TICK_TTMR_IE_SET(ttmr, 1);
ttmr = OR1K_SPR_TICK_TTMR_MODE_SET(ttmr, OR1K_SPR_TICK_TTMR_MODE_RESTART);
ttmr = OR1K_SPR_TICK_TTMR_IE_SET(ttmr, 1);
or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, ttmr);
}
/* --------------------------------------------------------------------------*/
/*!Enable tick timer
Install handler, calculate TTMR period, reset tick counter
@param[in] hz Rate at which to trigger timer ticks */
/* --------------------------------------------------------------------------*/
int
or1k_timer_init(unsigned int hz)
{
uint32_t upr = or1k_mfspr(OR1K_SPR_SYS_UPR_ADDR);
if (OR1K_SPR_SYS_UPR_TTP_GET(upr) == 0) {
return -1;
}
/* Set this, for easy access when reloading */
uint32_t period = (_or1k_board_clk_freq/hz) & OR1K_SPR_TICK_TTMR_TP_MASK;
OR1K_REENT.or1k_timer_period = period;
or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, period);
/* Reset timer tick counter */
OR1K_REENT.or1k_timer_ticks = 0;
/* Install handler */
or1k_exception_handler_add(0x5, _or1k_timer_interrupt_handler);
OR1K_REENT.or1k_timer_mode = OR1K_SPR_TICK_TTMR_MODE_RESTART;
/* Reset counter register */
or1k_mtspr(OR1K_SPR_TICK_TTCR_ADDR, 0);
return 0;
}
void
or1k_timer_set_period(uint32_t hz)
{
uint32_t period = (_or1k_board_clk_freq/hz) & OR1K_SPR_TICK_TTMR_TP_MASK;
uint32_t ttmr = or1k_mfspr(OR1K_SPR_TICK_TTMR_ADDR);
ttmr = OR1K_SPR_TICK_TTMR_TP_SET(ttmr, period);
or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, ttmr);
OR1K_REENT.or1k_timer_period = period;
}
void
or1k_timer_set_handler(void (*handler)(void))
{
or1k_exception_handler_add(0x5, handler);
}
void
or1k_timer_set_mode(uint32_t mode)
{
// Store mode in variable
OR1K_REENT.or1k_timer_mode = mode;
uint32_t ttmr = or1k_mfspr(OR1K_SPR_TICK_TTMR_ADDR);
// If the timer is currently running, we also change the mode
if (OR1K_SPR_TICK_TTMR_MODE_GET(ttmr) != 0) {
ttmr = OR1K_SPR_TICK_TTMR_MODE_SET(ttmr, mode);
or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, ttmr);
}
}
/* --------------------------------------------------------------------------*/
/*!Enable tick timer
Enable timer interrupt, install handler, load TTMR
*/
/* --------------------------------------------------------------------------*/
void
or1k_timer_enable(void)
{
uint32_t ttmr = or1k_mfspr(OR1K_SPR_TICK_TTMR_ADDR);
ttmr = OR1K_SPR_TICK_TTMR_IE_SET(ttmr, 1);
ttmr = OR1K_SPR_TICK_TTMR_MODE_SET(ttmr, OR1K_REENT.or1k_timer_mode);
or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, ttmr);
uint32_t sr = or1k_mfspr(OR1K_SPR_SYS_SR_ADDR);
sr = OR1K_SPR_SYS_SR_TEE_SET(sr, 1);
or1k_mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
}
/* --------------------------------------------------------------------------*/
/*!Disable tick timer
Disable timer interrupt in SR
*/
/* --------------------------------------------------------------------------*/
uint32_t
or1k_timer_disable(void)
{
uint32_t oldsr = or1k_mfspr(OR1K_SPR_SYS_SR_ADDR);
uint32_t sr = OR1K_SPR_SYS_SR_TEE_SET(oldsr, 0);
or1k_mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
return OR1K_SPR_SYS_SR_TEE_GET(oldsr);
}
void
or1k_timer_restore(uint32_t sr_tee)
{
uint32_t sr = or1k_mfspr(OR1K_SPR_SYS_SR_ADDR);
sr = OR1K_SPR_SYS_SR_TEE_SET(sr, 1);
or1k_mtspr(OR1K_SPR_SYS_SR_ADDR, sr);
}
void
or1k_timer_pause(void)
{
uint32_t ttmr = or1k_mfspr(OR1K_SPR_TICK_TTMR_ADDR);
ttmr = OR1K_SPR_TICK_TTMR_MODE_SET(ttmr, OR1K_SPR_TICK_TTMR_MODE_DISABLE);
or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, ttmr);
}
void
or1k_timer_reset(void)
{
uint32_t ttmr = or1k_mfspr(OR1K_SPR_TICK_TTMR_ADDR);
ttmr = OR1K_SPR_TICK_TTMR_IP_SET(ttmr, 0);
or1k_mtspr(OR1K_SPR_TICK_TTMR_ADDR, ttmr);
or1k_mtspr(OR1K_SPR_TICK_TTCR_ADDR, 0);
}
/* --------------------------------------------------------------------------*/
/*!Get tick timer
Return value of tick timer
*/
/* --------------------------------------------------------------------------*/
unsigned long
or1k_timer_get_ticks(void)
{
return OR1K_REENT.or1k_timer_ticks;
}
/* --------------------------------------------------------------------------*/
/*!Reset tick timer
Clear value of tick timer
*/
/* --------------------------------------------------------------------------*/
void
or1k_timer_reset_ticks(void)
{
OR1K_REENT.or1k_timer_ticks = 0;
}

83
libgloss/or1k/util.c Normal file
View File

@ -0,0 +1,83 @@
/* util.c -- Utility functions for OpenRISC 1000.
*
* 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.
*/
#include <stdint.h>
#include <stddef.h>
#include <reent.h>
#include "or1k-internals.h"
#ifdef __OR1K_MULTICORE__
uint32_t* *_or1k_stack_core;
uint32_t* *_or1k_exception_stack_core;
#endif
uint32_t* _or1k_stack_top;
uint32_t* _or1k_stack_bottom;
uint32_t* _or1k_exception_stack_top;
uint32_t* _or1k_exception_stack_bottom;
void _or1k_init() {
#ifdef __OR1K_MULTICORE__
uint32_t c;
// Initialize stacks
_or1k_stack_core = _sbrk_r(0, sizeof(uint32_t*) * or1k_numcores());
_or1k_exception_stack_core = _sbrk_r(0, sizeof(uint32_t*) * or1k_numcores());
_or1k_stack_core[0] = _or1k_stack_top;
_or1k_exception_stack_core[0] = _or1k_exception_stack_top;
for (c = 1; c < or1k_numcores(); c++) {
_or1k_stack_core[c] = _or1k_stack_core[c-1] - _or1k_stack_size;
_or1k_exception_stack_core[c] = _or1k_exception_stack_core[c-1] -
_or1k_exception_stack_size;
}
size_t exc_size = sizeof(void*) * or1k_numcores() * OR1K_NUM_EXCEPTIONS;
_or1k_exception_handler_table = _sbrk_r(0, exc_size);
size_t int_size = sizeof(void*) * or1k_numcores() * 32;
size_t intdata_size = sizeof(void*) * or1k_numcores() * 32;
_or1k_interrupt_handler_table = _sbrk_r(0, int_size);
_or1k_interrupt_handler_data_ptr_table = _sbrk_r(0, intdata_size);
#endif
_or1k_reent_init();
#ifdef __OR1K_MULTICORE__
for (c = 0; c < or1k_numcores(); c++) {
_or1k_exception_handler_table[c][6] = _or1k_interrupt_handler;
}
#else
_or1k_exception_handler_table[6] = _or1k_interrupt_handler;
#endif
}
uint32_t or1k_critical_begin() {
uint32_t iee = or1k_interrupts_disable();
uint32_t tee = or1k_timer_disable();
return (iee << 1) | tee;
}
void or1k_critical_end(uint32_t restore) {
or1k_timer_restore(restore & 0x1);
or1k_interrupts_restore((restore >> 1) & 0x1);
}