Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/newlib
diff options
context:
space:
mode:
authorJeff Johnston <jjohnstn@redhat.com>2008-06-10 06:13:22 +0400
committerJeff Johnston <jjohnstn@redhat.com>2008-06-10 06:13:22 +0400
commita0496b5e4f665e627005ed4fbc721f9dc52396b0 (patch)
tree224163f6b14f09227a89e2e55cb33df14d08b4a4 /newlib
parent27a07c4596d35cbe4b5bca2990e8ed371644d966 (diff)
2008-06-09 Ken Werner <ken.werner@de.ibm.com>
* libc/machine/spu/Makefile.am: Add new files. * libc/machine/spu/Makefile.in: Likewise. * libc/machine/spu/include/spu_timer.h: New file to add timer support using interrupts. * libc/machine/spu/spu_clock_stop.c: Likewise. * libc/machine/spu/spu_clock_svcs.c: Likewise. * libc/machine/spu/spu_timer_flih.S: Likewise. * libc/machine/spu/spu_timer_free.c: Likewise. * libc/machine/spu/spu_timer_internal.h: Likewise. * libc/machine/spu/spu_timer_slih.c: Likewise. * libc/machine/spu/spu_timer_slih_reg.c: Likewise. * libc/machine/spu/spu_timer_stop.c: Likewise. * libc/machine/spu/spu_timer_svcs.c: Likewise.
Diffstat (limited to 'newlib')
-rw-r--r--newlib/ChangeLog16
-rw-r--r--newlib/libc/machine/spu/Makefile.am4
-rw-r--r--newlib/libc/machine/spu/Makefile.in77
-rw-r--r--newlib/libc/machine/spu/include/spu_timer.h84
-rw-r--r--newlib/libc/machine/spu/spu_clock_stop.c67
-rw-r--r--newlib/libc/machine/spu/spu_clock_svcs.c93
-rw-r--r--newlib/libc/machine/spu/spu_timer_flih.S152
-rw-r--r--newlib/libc/machine/spu/spu_timer_free.c86
-rw-r--r--newlib/libc/machine/spu/spu_timer_internal.h140
-rw-r--r--newlib/libc/machine/spu/spu_timer_slih.c221
-rw-r--r--newlib/libc/machine/spu/spu_timer_slih_reg.c72
-rw-r--r--newlib/libc/machine/spu/spu_timer_stop.c101
-rw-r--r--newlib/libc/machine/spu/spu_timer_svcs.c115
13 files changed, 1217 insertions, 11 deletions
diff --git a/newlib/ChangeLog b/newlib/ChangeLog
index 13a4bb3c9..e68a1f4b6 100644
--- a/newlib/ChangeLog
+++ b/newlib/ChangeLog
@@ -1,5 +1,21 @@
2008-06-09 Ken Werner <ken.werner@de.ibm.com>
+ * libc/machine/spu/Makefile.am: Add new files.
+ * libc/machine/spu/Makefile.in: Likewise.
+ * libc/machine/spu/include/spu_timer.h: New file to add timer support
+ using interrupts.
+ * libc/machine/spu/spu_clock_stop.c: Likewise.
+ * libc/machine/spu/spu_clock_svcs.c: Likewise.
+ * libc/machine/spu/spu_timer_flih.S: Likewise.
+ * libc/machine/spu/spu_timer_free.c: Likewise.
+ * libc/machine/spu/spu_timer_internal.h: Likewise.
+ * libc/machine/spu/spu_timer_slih.c: Likewise.
+ * libc/machine/spu/spu_timer_slih_reg.c: Likewise.
+ * libc/machine/spu/spu_timer_stop.c: Likewise.
+ * libc/machine/spu/spu_timer_svcs.c: Likewise.
+
+2008-06-09 Ken Werner <ken.werner@de.ibm.com>
+
* libc/machine/spu/strcat.c: Return value fixed.
* libc/machine/spu/strncat.c: Likewise.
diff --git a/newlib/libc/machine/spu/Makefile.am b/newlib/libc/machine/spu/Makefile.am
index bd66094c5..fe4798e29 100644
--- a/newlib/libc/machine/spu/Makefile.am
+++ b/newlib/libc/machine/spu/Makefile.am
@@ -21,7 +21,9 @@ lib_a_SOURCES = setjmp.S assert.c clearerr.c creat.c fclose.c feof.c \
tmpnam.c ungetc.c usleep.c vfiprintf.c vfiscanf.c vfprintf.c \
vfscanf.c viprintf.c viscanf.c vprintf.c vscanf.c vsiprintf.c \
vsiscanf.c vsniprintf.c vsnprintf.c vsprintf.c vsscanf.c \
- stack_reg_va.S
+ stack_reg_va.S spu_clock_svcs.c spu_clock_stop.c spu_timer_flih.S \
+ spu_timer_slih.c spu_timer_slih_reg.c spu_timer_svcs.c \
+ spu_timer_stop.c spu_timer_free.c
lib_a_CCASFLAGS = $(AM_CCASFLAGS)
lib_a_CFLAGS = $(AM_CFLAGS)
diff --git a/newlib/libc/machine/spu/Makefile.in b/newlib/libc/machine/spu/Makefile.in
index 73464d5d9..941f010fc 100644
--- a/newlib/libc/machine/spu/Makefile.in
+++ b/newlib/libc/machine/spu/Makefile.in
@@ -74,7 +74,11 @@ DIST_COMMON = $(srcdir)/../../../../config.guess \
$(srcdir)/../../../../compile $(srcdir)/../../../../compile \
$(srcdir)/../../../../compile $(srcdir)/../../../../compile \
$(srcdir)/../../../../compile $(srcdir)/../../../../compile \
- $(srcdir)/../../../../compile $(srcdir)/../../../../compile
+ $(srcdir)/../../../../compile $(srcdir)/../../../../compile \
+ $(srcdir)/../../../../compile $(srcdir)/../../../../compile \
+ $(srcdir)/../../../../compile $(srcdir)/../../../../compile \
+ $(srcdir)/../../../../compile $(srcdir)/../../../../compile \
+ $(srcdir)/../../../../compile
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../../../acinclude.m4 \
@@ -131,7 +135,12 @@ am_lib_a_OBJECTS = lib_a-setjmp.$(OBJEXT) lib_a-assert.$(OBJEXT) \
lib_a-vscanf.$(OBJEXT) lib_a-vsiprintf.$(OBJEXT) \
lib_a-vsiscanf.$(OBJEXT) lib_a-vsniprintf.$(OBJEXT) \
lib_a-vsnprintf.$(OBJEXT) lib_a-vsprintf.$(OBJEXT) \
- lib_a-vsscanf.$(OBJEXT) lib_a-stack_reg_va.$(OBJEXT)
+ lib_a-vsscanf.$(OBJEXT) lib_a-stack_reg_va.$(OBJEXT) \
+ lib_a-spu_clock_svcs.$(OBJEXT) lib_a-spu_clock_stop.$(OBJEXT) \
+ lib_a-spu_timer_flih.$(OBJEXT) lib_a-spu_timer_slih.$(OBJEXT) \
+ lib_a-spu_timer_slih_reg.$(OBJEXT) \
+ lib_a-spu_timer_svcs.$(OBJEXT) lib_a-spu_timer_stop.$(OBJEXT) \
+ lib_a-spu_timer_free.$(OBJEXT)
lib_a_OBJECTS = $(am_lib_a_OBJECTS)
DEFAULT_INCLUDES = -I. -I$(srcdir)
depcomp =
@@ -205,6 +214,11 @@ STRIP = @STRIP@
USE_LIBTOOL_FALSE = @USE_LIBTOOL_FALSE@
USE_LIBTOOL_TRUE = @USE_LIBTOOL_TRUE@
VERSION = @VERSION@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_AS = @ac_ct_AS@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_READELF = @ac_ct_READELF@
+ac_ct_STRIP = @ac_ct_STRIP@
aext = @aext@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
@@ -220,23 +234,18 @@ build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
datadir = @datadir@
-datarootdir = @datarootdir@
-docdir = @docdir@
-dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
-htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
libm_machine_dir = @libm_machine_dir@
-localedir = @localedir@
localstatedir = @localstatedir@
lpfx = @lpfx@
machine_dir = @machine_dir@
@@ -245,10 +254,8 @@ mkdir_p = @mkdir_p@
newlib_basedir = @newlib_basedir@
oext = @oext@
oldincludedir = @oldincludedir@
-pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
-psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sys_dir = @sys_dir@
@@ -271,7 +278,9 @@ lib_a_SOURCES = setjmp.S assert.c clearerr.c creat.c fclose.c feof.c \
tmpnam.c ungetc.c usleep.c vfiprintf.c vfiscanf.c vfprintf.c \
vfscanf.c viprintf.c viscanf.c vprintf.c vscanf.c vsiprintf.c \
vsiscanf.c vsniprintf.c vsnprintf.c vsprintf.c vsscanf.c \
- stack_reg_va.S
+ stack_reg_va.S spu_clock_svcs.c spu_clock_stop.c spu_timer_flih.S \
+ spu_timer_slih.c spu_timer_slih_reg.c spu_timer_svcs.c \
+ spu_timer_stop.c spu_timer_free.c
lib_a_CCASFLAGS = $(AM_CCASFLAGS)
lib_a_CFLAGS = $(AM_CFLAGS)
@@ -430,6 +439,12 @@ lib_a-stack_reg_va.o: stack_reg_va.S
lib_a-stack_reg_va.obj: stack_reg_va.S
$(CCAS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-stack_reg_va.obj `if test -f 'stack_reg_va.S'; then $(CYGPATH_W) 'stack_reg_va.S'; else $(CYGPATH_W) '$(srcdir)/stack_reg_va.S'; fi`
+lib_a-spu_timer_flih.o: spu_timer_flih.S
+ $(CCAS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-spu_timer_flih.o `test -f 'spu_timer_flih.S' || echo '$(srcdir)/'`spu_timer_flih.S
+
+lib_a-spu_timer_flih.obj: spu_timer_flih.S
+ $(CCAS) $(lib_a_CCASFLAGS) $(CCASFLAGS) -c -o lib_a-spu_timer_flih.obj `if test -f 'spu_timer_flih.S'; then $(CYGPATH_W) 'spu_timer_flih.S'; else $(CYGPATH_W) '$(srcdir)/spu_timer_flih.S'; fi`
+
.c.o:
$(COMPILE) -c $<
@@ -855,6 +870,48 @@ lib_a-vsscanf.o: vsscanf.c
lib_a-vsscanf.obj: vsscanf.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-vsscanf.obj `if test -f 'vsscanf.c'; then $(CYGPATH_W) 'vsscanf.c'; else $(CYGPATH_W) '$(srcdir)/vsscanf.c'; fi`
+
+lib_a-spu_clock_svcs.o: spu_clock_svcs.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_clock_svcs.o `test -f 'spu_clock_svcs.c' || echo '$(srcdir)/'`spu_clock_svcs.c
+
+lib_a-spu_clock_svcs.obj: spu_clock_svcs.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_clock_svcs.obj `if test -f 'spu_clock_svcs.c'; then $(CYGPATH_W) 'spu_clock_svcs.c'; else $(CYGPATH_W) '$(srcdir)/spu_clock_svcs.c'; fi`
+
+lib_a-spu_clock_stop.o: spu_clock_stop.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_clock_stop.o `test -f 'spu_clock_stop.c' || echo '$(srcdir)/'`spu_clock_stop.c
+
+lib_a-spu_clock_stop.obj: spu_clock_stop.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_clock_stop.obj `if test -f 'spu_clock_stop.c'; then $(CYGPATH_W) 'spu_clock_stop.c'; else $(CYGPATH_W) '$(srcdir)/spu_clock_stop.c'; fi`
+
+lib_a-spu_timer_slih.o: spu_timer_slih.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_slih.o `test -f 'spu_timer_slih.c' || echo '$(srcdir)/'`spu_timer_slih.c
+
+lib_a-spu_timer_slih.obj: spu_timer_slih.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_slih.obj `if test -f 'spu_timer_slih.c'; then $(CYGPATH_W) 'spu_timer_slih.c'; else $(CYGPATH_W) '$(srcdir)/spu_timer_slih.c'; fi`
+
+lib_a-spu_timer_slih_reg.o: spu_timer_slih_reg.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_slih_reg.o `test -f 'spu_timer_slih_reg.c' || echo '$(srcdir)/'`spu_timer_slih_reg.c
+
+lib_a-spu_timer_slih_reg.obj: spu_timer_slih_reg.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_slih_reg.obj `if test -f 'spu_timer_slih_reg.c'; then $(CYGPATH_W) 'spu_timer_slih_reg.c'; else $(CYGPATH_W) '$(srcdir)/spu_timer_slih_reg.c'; fi`
+
+lib_a-spu_timer_svcs.o: spu_timer_svcs.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_svcs.o `test -f 'spu_timer_svcs.c' || echo '$(srcdir)/'`spu_timer_svcs.c
+
+lib_a-spu_timer_svcs.obj: spu_timer_svcs.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_svcs.obj `if test -f 'spu_timer_svcs.c'; then $(CYGPATH_W) 'spu_timer_svcs.c'; else $(CYGPATH_W) '$(srcdir)/spu_timer_svcs.c'; fi`
+
+lib_a-spu_timer_stop.o: spu_timer_stop.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_stop.o `test -f 'spu_timer_stop.c' || echo '$(srcdir)/'`spu_timer_stop.c
+
+lib_a-spu_timer_stop.obj: spu_timer_stop.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_stop.obj `if test -f 'spu_timer_stop.c'; then $(CYGPATH_W) 'spu_timer_stop.c'; else $(CYGPATH_W) '$(srcdir)/spu_timer_stop.c'; fi`
+
+lib_a-spu_timer_free.o: spu_timer_free.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_free.o `test -f 'spu_timer_free.c' || echo '$(srcdir)/'`spu_timer_free.c
+
+lib_a-spu_timer_free.obj: spu_timer_free.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib_a_CFLAGS) $(CFLAGS) -c -o lib_a-spu_timer_free.obj `if test -f 'spu_timer_free.c'; then $(CYGPATH_W) 'spu_timer_free.c'; else $(CYGPATH_W) '$(srcdir)/spu_timer_free.c'; fi`
uninstall-info-am:
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
diff --git a/newlib/libc/machine/spu/include/spu_timer.h b/newlib/libc/machine/spu/include/spu_timer.h
new file mode 100644
index 000000000..ea10ce57d
--- /dev/null
+++ b/newlib/libc/machine/spu/include/spu_timer.h
@@ -0,0 +1,84 @@
+/*
+(C) Copyright IBM Corp. 2008
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of IBM nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+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 OWNER 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 _SPU_TIMER_H_
+#define _SPU_TIMER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+/* Clock services. */
+extern void spu_clock_start (void);
+extern int spu_clock_stop (void);
+extern uint64_t spu_clock_read (void);
+
+/* Timer services. */
+extern int spu_timer_alloc (int interval, void (*func) (int));
+extern int spu_timer_free (int id);
+extern int spu_timer_start (int id);
+extern int spu_timer_stop (int id);
+
+/* Interrupt services. */
+extern void spu_slih_register (unsigned event_mask,
+ unsigned (*slih) (unsigned));
+extern unsigned spu_clock_slih (unsigned event_mask);
+
+/* Number of supported timers. */
+#define SPU_TIMER_NTIMERS 4
+
+/* Recommended minimun spu timer interval time from (cat /proc/cpuinfo)
+ * QS20 100/14318000 = 6.98 usec
+ * QS21/QS22 100/26666666 = 3.75 usec
+ * PS3 100/79800000 = 1.25 usec */
+#define SPU_TIMER_MIN_INTERVAL 100
+
+/* Clock error codes. */
+#define SPU_CLOCK_ERR_NOT_RUNNING -2
+#define SPU_CLOCK_ERR_STILL_RUNNING -3
+#define SPU_CLOCK_ERR_TIMERS_ACTIVE -4
+
+/* Timer error codes. */
+#define SPU_TIMER_ERR_INVALID_PARM -10
+#define SPU_TIMER_ERR_NONE_FREE -11
+#define SPU_TIMER_ERR_INVALID_ID -12
+#define SPU_TIMER_ERR_ACTIVE -13
+#define SPU_TIMER_ERR_NOT_ACTIVE -14
+#define SPU_TIMER_ERR_NOCLOCK -15
+#define SPU_TIMER_ERR_FREE -16
+#define SPU_TIMER_ERR_NOT_STOPPED -17
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/newlib/libc/machine/spu/spu_clock_stop.c b/newlib/libc/machine/spu/spu_clock_stop.c
new file mode 100644
index 000000000..da31b42c6
--- /dev/null
+++ b/newlib/libc/machine/spu/spu_clock_stop.c
@@ -0,0 +1,67 @@
+/*
+(C) Copyright IBM Corp. 2008
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of IBM nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+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 OWNER 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.
+*/
+
+/* SPU clock stop library service. */
+#include <spu_timer.h>
+#include "spu_timer_internal.h"
+
+/* Stops the SPU clock:
+ * decrements clock start count
+ * when count is zero, disables the decrementer event and stops the
+ decrementer
+ Returns 0 on success and <0 on failure:
+ * SPU_CLOCK_ERR_NOT_RUNNING - clock was already off
+ * SPU_CLOCK_ERR_TIMERS_ACTIVE - active timers exist
+ * SPU_CLOCK_ERR_STILL_RUNNING - start count was decremented but clock was
+ not stopped */
+int
+spu_clock_stop (void)
+{
+ if (__spu_clock_startcnt == 0)
+ return SPU_CLOCK_ERR_NOT_RUNNING;
+
+ if (__spu_clock_startcnt == 1 && (__spu_timers_active || __spu_timers_handled))
+ return SPU_CLOCK_ERR_TIMERS_ACTIVE;
+
+ /* Don't stop clock if the clock is still in use. */
+ if (--__spu_clock_startcnt != 0)
+ return SPU_CLOCK_ERR_STILL_RUNNING;
+
+ /* Clock stopped, stop decrementer. */
+ __disable_spu_decr ();
+
+ /* Clock is enabled on clock start - restore to original state (saved at start). */
+ if (__likely (!__spu_clock_state_was_enabled))
+ {
+ spu_idisable ();
+ }
+
+ return 0;
+}
diff --git a/newlib/libc/machine/spu/spu_clock_svcs.c b/newlib/libc/machine/spu/spu_clock_svcs.c
new file mode 100644
index 000000000..6cc2af4a9
--- /dev/null
+++ b/newlib/libc/machine/spu/spu_clock_svcs.c
@@ -0,0 +1,93 @@
+/*
+(C) Copyright IBM Corp. 2008
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of IBM nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+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 OWNER 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.
+*/
+
+/* SPU clock start and read library services. */
+#include <spu_timer.h>
+#include "spu_timer_internal.h"
+
+/* The software managed timebase value. */
+volatile uint64_t __spu_tb_val __attribute__ ((aligned (16)));
+
+/* Timeout value of the current interval. */
+volatile int __spu_tb_timeout __attribute__ ((aligned (16)));
+
+/* Clock start count (clock is running if >0). */
+volatile unsigned __spu_clock_startcnt __attribute__ ((aligned (16)));
+
+/* Saved interrupt state from clock_start. */
+volatile unsigned __spu_clock_state_was_enabled;
+
+/* Initializes the software managed timebase, enables the decrementer event,
+ starts the decrementer and enables interrupts. Must be called before
+ clock or timer services can be used. Should only be called by base app/lib
+ code (not from an interrupt/timer handler).
+ Returns with interrupts ENABLED. */
+void
+spu_clock_start (void)
+{
+ /* Increment clock start and return if it was already running. */
+ if (++__spu_clock_startcnt > 1)
+ return;
+
+ __spu_clock_state_was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
+
+ spu_idisable ();
+ __spu_tb_timeout = CLOCK_START_VALUE;
+ __spu_tb_val = 0;
+
+ /* Disable, write, enable the decrementer. */
+ __enable_spu_decr (__spu_tb_timeout, __disable_spu_decr ());
+
+ spu_ienable ();
+
+ return;
+}
+
+/* Returns a monotonically increasing, 64-bit counter, in timebase units,
+ relative to the last call to spu_clock_start(). */
+uint64_t
+spu_clock_read (void)
+{
+ int64_t time;
+ unsigned was_enabled;
+
+ /* Return 0 if clock is off. */
+ if (__spu_clock_startcnt == 0)
+ return 0LL;
+
+ was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
+ spu_idisable ();
+
+ time = __spu_tb_val + (__spu_tb_timeout - spu_readch (SPU_RdDec));
+
+ if (__likely (was_enabled))
+ spu_ienable ();
+ return time;
+}
diff --git a/newlib/libc/machine/spu/spu_timer_flih.S b/newlib/libc/machine/spu/spu_timer_flih.S
new file mode 100644
index 000000000..63f5f074c
--- /dev/null
+++ b/newlib/libc/machine/spu/spu_timer_flih.S
@@ -0,0 +1,152 @@
+/*
+(C) Copyright IBM Corp. 2008
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of IBM nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+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 OWNER 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.
+*/
+
+/* First-level interrupt handler. */
+
+/* The following two convenience macros assist in the coding of the
+ saving and restoring the volatile register starting from register
+ 2 up to register 79.
+
+ saveregs first, last Saves registers from first to the last.
+ restoreregs first, last Restores registers from last down to first.
+
+ Note: first must be less than or equal to last. */
+
+.macro saveregs first, last
+ stqd $\first, -(STACK_SKIP+\first)*16($SP)
+.if \last-\first
+ saveregs "(\first+1)",\last
+.endif
+.endm
+
+
+.macro restoreregs first, last
+ lqd $\last, (82-\last)*16($SP)
+.if \last-\first
+ restoreregs \first,"(\last-1)"
+.endif
+.endm
+
+ .section .interrupt,"ax"
+ .align 3
+ .type spu_flih, @function
+spu_flih:
+ /* Adjust the stack pointer to skip the maximum register save area
+ (STACK_SKIP quadword registers) in case an interrupt occurred while
+ executing a leaf function that used the stack area without actually
+ allocating its own stack frame. */
+ .set STACK_SKIP, 125
+
+ /* Save the current link register on a new stack frame for the
+ normal spu_flih() version of this file. */
+ stqd $0, -(STACK_SKIP+80)*16($SP)
+ stqd $SP, -(STACK_SKIP+82)*16($SP) /* Save back chain pointer. */
+
+ saveregs 2, 39
+
+ il $2, -(STACK_SKIP+82)*16 /* Stack frame size. */
+ rdch $3, $SPU_RdEventStat /* Read event status. */
+
+ rdch $6, $SPU_RdEventMask /* Read event mask. */
+ hbrp /* Open a slot for instruction prefetch. */
+
+ saveregs 40,59
+
+ clz $4, $3 /* Get first slih index. */
+ stqd $6, -(STACK_SKIP+1)*16($SP) /* Save event mask on stack. */
+
+ saveregs 60, 67
+
+ /* Do not disable/ack the decrementer event here.
+ The timer library manages this and expects it
+ to be enabled upon entry to the SLIH. */
+ il $7, 0x20
+ andc $5, $3, $7
+ andc $7, $6, $5 /* Clear event bits. */
+ saveregs 68, 69
+
+ wrch $SPU_WrEventAck, $3 /* Ack events(s) - include decrementer event. */
+ wrch $SPU_WrEventMask, $7 /* Disable event(s) - exclude decrementer event. */
+
+ saveregs 70, 79
+
+ a $SP, $SP, $2 /* Instantiate flih stack frame. */
+next_event:
+ /* Fetch and dispatch the event handler for the first non-zero event. The
+ dispatch handler is indexed into the __spu_slih_handlers array using the
+ count of zero off the event status as an index. */
+ ila $5, __spu_slih_handlers /* Slih array offset. */
+
+ shli $4, $4, 2 /* Slih entry offset. */
+ lqx $5, $4, $5 /* Load slih address. */
+ rotqby $5, $5, $4 /* Rotate to word 0. */
+ bisl $0, $5 /* Branch to slih. */
+
+ clz $4, $3 /* Get next slih index. */
+ brnz $3, next_event
+
+
+ lqd $2, 81*16($SP) /* Read event mask from stack. */
+
+ restoreregs 40, 79
+
+ wrch $SPU_WrEventMask, $2 /* Restore event mask. */
+ hbrp /* Open a slot for instruction pre-fetch. */
+
+ restoreregs 2, 39
+
+ /* Restore the link register from the new stack frame for the
+ normal spu_flih() version of this file. */
+ lqd $0, 2*16($SP)
+
+ lqd $SP, 0*16($SP) /* restore stack pointer from back chain ptr. */
+
+ irete /* Return from interrupt and re-enable interrupts. */
+ .size spu_flih, .-spu_flih
+/* spu_slih_handlers[]
+ Here we initialize 33 default event handlers. The first entry in this array
+ corresponds to the event handler for the event associated with bit 0 of
+ Channel 0 (External Event Status). The 32nd entry in this array corresponds
+ to bit 31 of Channel 0 (DMA Tag Status Update Event). The 33rd entry in
+ this array is a special case entry to handle "phantom events" which occur
+ when the channel count for Channel 0 is 1, causing an asynchronous SPU
+ interrupt, but the value returned for a read of Channel 0 is 0. The index
+ calculated into this array by spu_flih() for this case is 32, hence the
+ 33rd entry. */
+.data
+ .align 4
+ .extern __spu_default_slih
+ .global __spu_slih_handlers
+ .type __spu_slih_handlers, @object
+__spu_slih_handlers:
+ .rept 33
+ .long __spu_default_slih
+ .endr
+ .size __spu_slih_handlers, .-__spu_slih_handlers
diff --git a/newlib/libc/machine/spu/spu_timer_free.c b/newlib/libc/machine/spu/spu_timer_free.c
new file mode 100644
index 000000000..9fb3e0cda
--- /dev/null
+++ b/newlib/libc/machine/spu/spu_timer_free.c
@@ -0,0 +1,86 @@
+/*
+(C) Copyright IBM Corp. 2008
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of IBM nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+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 OWNER 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.
+*/
+
+/* SPU timer free library service. */
+#include <spu_timer.h>
+#include "spu_timer_internal.h"
+
+
+/* Frees an allocated timer. The timer must be in the stopped state for this
+ to succeed. Maybe be called:
+ * after allocated, before it's started
+ * after it's been explicitly stopped
+ Returns 0 on success, timer sucessfully deallocated. Returns <0 on failure
+ * SPU_TIMER_INVALID_ID - id out of range
+ * SPU_TIMER_ERR_FREE - id in free state
+ * SPU_TIMER_ERR_ACTIVE - id in handled or active state */
+int
+spu_timer_free (int id)
+{
+ spu_timer_t *t, **pn;
+ unsigned was_enabled;
+
+ if (id < 0 || id >= SPU_TIMER_NTIMERS)
+ return SPU_TIMER_ERR_INVALID_ID;
+
+ if (__spu_timers[id].state == SPU_TIMER_STOPPED)
+ {
+
+ was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
+ spu_idisable ();
+
+ t = __spu_timers_stopped;
+ pn = &__spu_timers_stopped;
+
+ while (t && (t->id != id))
+ {
+ pn = &t->next;
+ t = t->next;
+ }
+#ifdef SPU_TIMER_DEBUG
+ if (!t)
+ ABORT ();
+#endif
+ *pn = t->next;
+
+ /* Add timer back to free list (mask). */
+ __spu_timers_avail |= (1 << (id));
+ __spu_timers[id].state = SPU_TIMER_FREE;
+
+ if (__likely (was_enabled))
+ spu_ienable ();
+
+ return 0;
+ }
+
+ /* Handle invalid states. */
+ return (__spu_timers[id].state == SPU_TIMER_FREE) ?
+ SPU_TIMER_ERR_FREE : SPU_TIMER_ERR_ACTIVE;
+}
diff --git a/newlib/libc/machine/spu/spu_timer_internal.h b/newlib/libc/machine/spu/spu_timer_internal.h
new file mode 100644
index 000000000..a438561b9
--- /dev/null
+++ b/newlib/libc/machine/spu/spu_timer_internal.h
@@ -0,0 +1,140 @@
+/*
+(C) Copyright IBM Corp. 2008
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of IBM nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+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 OWNER 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.
+*/
+
+/* Internal definitions for SPU timer library. */
+#ifndef _SPU_TIMER_INTERNAL_H_
+#define _SPU_TIMER_INTERNAL_H_
+
+#include <spu_intrinsics.h>
+#include <spu_mfcio.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#ifdef SPU_TIMER_DEBUG
+#include <stdio.h>
+#include <assert.h>
+#endif
+
+/* The timer state tells which list its on. */
+typedef enum spu_timer_state
+{
+ SPU_TIMER_FREE = 0,
+ SPU_TIMER_ACTIVE = 1,
+ SPU_TIMER_HANDLED = 2,
+ SPU_TIMER_STOPPED = 3
+} spu_timer_state_t;
+
+typedef struct spu_timer
+{
+ int tmout __attribute__ ((aligned (16))); /* Time until expiration (tb). */
+ int intvl __attribute__ ((aligned (16))); /* Interval. */
+ int id __attribute__ ((aligned (16)));
+ spu_timer_state_t state __attribute__ ((aligned (16)));
+ void (*func) (int) __attribute__ ((aligned (16))); /* Handler. */
+ struct spu_timer *next __attribute__ ((aligned (16)));
+} spu_timer_t;
+
+
+/* Max decrementer value. */
+#define DECR_MAX 0xFFFFFFFFU
+
+ /* Arbitrary non-triggering value. */
+#define CLOCK_START_VALUE 0x7FFFFFFF
+
+#define MIN_INTVL 1
+#define MAX_INTVL INT_MAX
+
+/* Timers within 15 tics will expire together. */
+#define TIMER_INTERVAL_WINDOW 15
+
+/* Disables the decrementer and returns the saved event mask for a subsequent
+ call to __enable_spu_decr. The decrementer interrupt is acknowledged in the
+ flih when the event is received, but is required also as part of the
+ procedure to stop the decrementer. */
+static inline unsigned
+__disable_spu_decr (void)
+{
+ unsigned mask = spu_readch (SPU_RdEventMask);
+ spu_writech (SPU_WrEventMask, mask & ~MFC_DECREMENTER_EVENT);
+ spu_writech (SPU_WrEventAck, MFC_DECREMENTER_EVENT);
+ spu_sync_c ();
+ return mask;
+}
+
+/* Writes and enables the decrementer, along with the given event mask. */
+static inline void
+__enable_spu_decr (int val, unsigned mask)
+{
+ spu_writech (SPU_WrDec, (val));
+ spu_writech (SPU_WrEventMask, mask | MFC_DECREMENTER_EVENT);
+ spu_sync_c ();
+}
+
+/* These are shared between modules but are not inlined, to save space. */
+extern void __spu_timer_start (int id, int reset);
+extern void __reset_spu_decr (int val);
+
+/* The timers. */
+extern spu_timer_t __spu_timers[];
+
+/* Active timer list. */
+extern spu_timer_t *__spu_timers_active;
+
+/* Stopped (allocated) timer list. */
+extern spu_timer_t *__spu_timers_stopped;
+
+/* List of timers being handled. */
+extern spu_timer_t *__spu_timers_handled;
+
+/* Bitmask of available timers. */
+extern unsigned __spu_timers_avail;
+
+/* The software managed timebase value. */
+extern volatile uint64_t __spu_tb_val;
+
+/* Timeout value of the current interval. */
+extern volatile int __spu_tb_timeout;
+
+/* Clock start count (clock is running if >0). */
+extern volatile unsigned __spu_clock_startcnt;
+
+/* Saved interrupt state from clock_start. */
+extern volatile unsigned __spu_clock_state_was_enabled;
+
+#define __likely(_c) __builtin_expect((_c), 1)
+#define __unlikely(_c) __builtin_expect((_c), 0)
+
+#define ABORT() \
+{\
+ fprintf(stderr, "Internal error, aborting: %s:%d\n", __FILE__, __LINE__);\
+ assert(0);\
+}
+
+#endif
diff --git a/newlib/libc/machine/spu/spu_timer_slih.c b/newlib/libc/machine/spu/spu_timer_slih.c
new file mode 100644
index 000000000..93cfa5ea2
--- /dev/null
+++ b/newlib/libc/machine/spu/spu_timer_slih.c
@@ -0,0 +1,221 @@
+/*
+(C) Copyright IBM Corp. 2008
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of IBM nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+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 OWNER 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.
+*/
+
+/* Second Level Interrupt handler and related services for SPU timers. */
+#include "spu_timer_internal.h"
+/* Resets decrementer to the specified value. Also updates software timebase
+ to account for the time between the last decrementer reset and now. There
+ are two cases:
+ * Called by application to start a new timer.
+ * Called by spu_clock to active the next timer.
+ In both cases, the amount of time is the current interval timeout minus the
+ current decrementer value. */
+void
+__reset_spu_decr (int val)
+{
+
+ /* The interrupt occurs when the msb goes from 0 to 1 or when the decrementer
+ goes from 0 to -1. To be precisely accurate we should set the timer to
+ the intverval -1, unless the interval passed in is 0 in which case it
+ should be left at 0. */
+ int enable_val = (__likely (val)) ? val - 1 : 0;
+
+ /* Decrementer must be stopped before writing it - minimize the time
+ stopped. */
+ unsigned mask = __disable_spu_decr ();
+
+ /* Perform tb correction before resettting the decrementer. the corrected
+ value is the current timeout value minus the current decrementer value.
+ Occasionally the read returns 0 - a second read will clear this
+ condition. */
+ int decval0 = spu_readch (SPU_RdDec);
+ int decval = spu_readch (SPU_RdDec);
+ /* Restart decrementer with next timeout val. */
+ __enable_spu_decr (enable_val, mask);
+
+ /* Update the timebase values before enabling for interrupts. */
+ __spu_tb_val += __spu_tb_timeout - decval;
+ __spu_tb_timeout = enable_val;
+}
+
+/* Update software timebase and timeout value for the 'next to expire' timer.
+ Called when starting a new timer so the timer list will have timeouts
+ relative to the current time. */
+static inline void
+__update_spu_tb_val (void)
+{
+ int elapsed = __spu_tb_timeout - spu_readch (SPU_RdDec);
+#ifdef SPU_TIMER_DEBUG
+ if (elapsed < 0)
+ ABORT ();
+#endif
+ __spu_tb_val += elapsed;
+
+ /* Adjust the timeout for the timer next to expire. Note this could cause
+ the timeout to go negative, if it was just about to expire when we called
+ spu_timer_start. This is OK, since this can happen any time interrupts
+ are disabled. We just schedule an immediate timeout in this case. */
+ if (__spu_timers_active)
+ {
+ __spu_timers_active->tmout -= elapsed;
+ if (__spu_timers_active->tmout < 0)
+ __spu_timers_active->tmout = 0;
+ }
+}
+
+/* Add an allocated timer to the active list. The active list is sorted by
+ timeout value. The timer at the head of the list is the timer that will
+ expire next. The rest of the timers have a timeout value that is relative
+ to the timer ahead of it on the list. This relative value is determined
+ here, when the timer is added to the active list. When its position in the
+ list is found, the timer's timeout value is set to its interval minus the
+ sum of all the timeout values ahead of it. The timeout value for the timer
+ following the newly added timer is then adjusted to a new relative value. If
+ the newly added timer is at the head of the list, the decrementer is reset.
+ This function is called by SLIH to restart multiple timers (reset == 0) or
+ by spu_timer_start() to start a single timer (reset == 1). */
+void
+__spu_timer_start (int id, int reset)
+{
+ spu_timer_t *t;
+ spu_timer_t **pn;
+ spu_timer_t *start = &__spu_timers[id];
+ unsigned tmout_time = 0;
+ unsigned my_intvl = start->intvl;
+ unsigned was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
+
+ spu_idisable ();
+
+ t = __spu_timers_active;
+ pn = &__spu_timers_active;
+
+ /* If the active list is empty, just add the timer with the timeout set to
+ the interval. Otherwise find the place in the list for the timer, setting
+ its timeout to its interval minus the sum of timeouts ahead of it. */
+ start->state = SPU_TIMER_ACTIVE;
+ if (__likely (!t))
+ {
+ __spu_timers_active = start;
+ start->next = NULL;
+ start->tmout = my_intvl;
+ }
+ else
+ {
+
+ /* Update swtb and timeout val of the next timer, so all times are
+ relative to now. */
+ if (reset)
+ __update_spu_tb_val ();
+
+ while (t && (my_intvl >= (tmout_time + t->tmout)))
+ {
+ tmout_time += t->tmout;
+ pn = &t->next;;
+ t = t->next;
+ }
+ start->next = t;
+ start->tmout = my_intvl - tmout_time;
+ *pn = start;
+
+ /* Adjust timeout for timer after us. */
+ if (t)
+ t->tmout -= start->tmout;
+ }
+
+ if (reset && (__spu_timers_active == start))
+ __reset_spu_decr (__spu_timers_active->tmout);
+
+ if (__unlikely (was_enabled))
+ spu_ienable ();
+}
+
+/* SLIH for decrementer. Manages software timebase and timers.
+ Called by SPU FLIH. Assumes decrementer is still running
+ (event not yet acknowledeged). */
+unsigned int
+spu_clock_slih (unsigned status)
+{
+ int decr_reset_val;
+ spu_timer_t *active, *handled;
+ unsigned was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
+
+ status &= ~MFC_DECREMENTER_EVENT;
+
+ spu_idisable ();
+
+ /* The decrementer has now expired. The decrementer event was acknowledged
+ in the FLIH but not disabled. The decrementer will continue to run while
+ we're running the clock/timer handler. The software clock keeps running,
+ and accounts for all the time spent running handlers. Add the current
+ timeout to the software timebase and set the timeout to DECR_MAX. This
+ allows the "clock read" code to continue to work while we're in here, and
+ gives us the most possible time to finish before another underflow. */
+ __spu_tb_val += __spu_tb_timeout;
+ __spu_tb_timeout = DECR_MAX;
+
+ /* For all timers that have the current timeout value, move them from the
+ active list to the handled list and call their handlers. Note that the
+ handled/stopped lists may be manipulated by the handlers if they wish to
+ stop/free the timers. Note that only the first expired timer will reflect
+ the real timeout value; the rest of the timers that had the same timeout
+ value will have a relative value of zero. */
+ if (__spu_timers_active)
+ {
+ __spu_timers_active->tmout = 0;
+ while ((active = __spu_timers_active)
+ && (active->tmout <= TIMER_INTERVAL_WINDOW))
+ {
+ __spu_timers_active = active->next;
+ active->next = __spu_timers_handled;
+ __spu_timers_handled = active;
+ active->state = SPU_TIMER_HANDLED;
+ (*active->func) (active->id);
+ }
+ }
+
+ /* put the handled timers back on the list and restart decrementer. */
+ while ((handled = __spu_timers_handled) != NULL)
+ {
+ __spu_timers_handled = handled->next;
+ __spu_timer_start (handled->id, 0);
+ }
+
+ /* Reset the decrementer before returning. If we have any active timers, we
+ set it to the timeout value for the timer at the head of the list, else
+ the default clock value. */
+ decr_reset_val = __spu_timers_active ? __spu_timers_active->tmout : CLOCK_START_VALUE;
+
+ __reset_spu_decr (decr_reset_val);
+
+ if (__likely (was_enabled))
+ spu_ienable ();
+
+ return status;
+}
diff --git a/newlib/libc/machine/spu/spu_timer_slih_reg.c b/newlib/libc/machine/spu/spu_timer_slih_reg.c
new file mode 100644
index 000000000..cd1e86fbb
--- /dev/null
+++ b/newlib/libc/machine/spu/spu_timer_slih_reg.c
@@ -0,0 +1,72 @@
+/*
+(C) Copyright IBM Corp. 2008
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of IBM nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+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 OWNER 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.
+*/
+
+
+/* Services for SLIH registration. */
+#include <spu_intrinsics.h>
+#include <spu_timer.h>
+
+#define SPU_EVENT_ID(_mask) \
+ (spu_extract(spu_cntlz(spu_promote(_mask, 0)), 0))
+typedef unsigned (*spu_slih_t) (unsigned);
+
+extern spu_slih_t __spu_slih_handlers[];
+
+/* This function is called whenever an event occurs for which no second level
+ event handler was registered. The default event handler does nothing and
+ zeros the most significant event bit indicating that the event was processed
+ (when in reality, it was discarded). */
+unsigned
+__spu_default_slih (unsigned events)
+{
+ unsigned int mse;
+
+ mse = 0x80000000 >> SPU_EVENT_ID (events);
+ events &= ~mse;
+
+ return (events);
+}
+
+/* Registers a SPU second level interrupt handler for the events specified by
+ mask. The event mask consists of a set of bits corresponding to the event
+ status bits (see channel 0 description). A mask containing multiple 1 bits
+ will set the second level event handler for each of the events. */
+void
+spu_slih_register (unsigned mask, spu_slih_t func)
+{
+ unsigned int id;
+
+ while (mask)
+ {
+ id = SPU_EVENT_ID (mask);
+ __spu_slih_handlers[id] = (func) ? func : __spu_default_slih;
+ mask &= ~(0x80000000 >> id);
+ }
+}
diff --git a/newlib/libc/machine/spu/spu_timer_stop.c b/newlib/libc/machine/spu/spu_timer_stop.c
new file mode 100644
index 000000000..94286c914
--- /dev/null
+++ b/newlib/libc/machine/spu/spu_timer_stop.c
@@ -0,0 +1,101 @@
+/*
+(C) Copyright IBM Corp. 2008
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of IBM nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+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 OWNER 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.
+*/
+
+/* SPU timer stop library service. */
+#include <spu_timer.h>
+#include "spu_timer_internal.h"
+
+/* Stop a timer. Moves it from either the active or handled list to the
+ stopped list. Returns 0 on sucess, timer was successfully stopped.
+ Returns <0 - Failure:
+ * SPU_TIMER_ERR_NOT_ACTIVE - timer was not active
+ * SPU_TIMER_ERR_INVALID_ID - invalid timer id
+ * SPU_TIMER_ERR_NOCLOCK - spu clock is not running */
+int
+spu_timer_stop (int id)
+{
+ spu_timer_t *t, **pn;
+ unsigned was_enabled;
+
+ if (id < 0 || id >= SPU_TIMER_NTIMERS)
+ return SPU_TIMER_ERR_INVALID_ID;
+
+ if (__spu_clock_startcnt == 0)
+ return SPU_TIMER_ERR_NOCLOCK;
+
+
+ /* Free or stopped states. */
+ if (__spu_timers[id].state == SPU_TIMER_ACTIVE ||
+ __spu_timers[id].state == SPU_TIMER_HANDLED)
+ {
+ was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
+ spu_idisable ();
+
+ /* Timer is on either active list or handled list. */
+ t = (__spu_timers[id].state == SPU_TIMER_ACTIVE)
+ ? __spu_timers_active : __spu_timers_handled;
+
+ pn = (__spu_timers[id].state == SPU_TIMER_ACTIVE)
+ ? &__spu_timers_active : &__spu_timers_handled;
+
+ while (t && t->id != id)
+ {
+ pn = &t->next;
+ t = t->next;
+ }
+#ifdef SPU_TIMER_DEBUG
+ if (!t)
+ ABORT (); /* Internal error. */
+#endif
+ /* Fix timeout of next timer and decrementer if we were at the head of
+ the active list. */
+ if (t->next)
+ {
+ t->next->tmout += t->tmout;
+ if (__spu_timers_active == t)
+ __reset_spu_decr (t->next->tmout);
+ }
+ else
+ __reset_spu_decr (CLOCK_START_VALUE);
+
+ *pn = t->next; /* Update this elements to pointer. */
+ t->next = __spu_timers_stopped;
+ __spu_timers_stopped = t;
+
+ __spu_timers[id].state = SPU_TIMER_STOPPED;
+
+ if (__likely (was_enabled))
+ spu_ienable ();
+
+ return 0;
+ }
+
+ return SPU_TIMER_ERR_NOT_ACTIVE;
+}
diff --git a/newlib/libc/machine/spu/spu_timer_svcs.c b/newlib/libc/machine/spu/spu_timer_svcs.c
new file mode 100644
index 000000000..8e7013ccd
--- /dev/null
+++ b/newlib/libc/machine/spu/spu_timer_svcs.c
@@ -0,0 +1,115 @@
+/*
+(C) Copyright IBM Corp. 2008
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+* Neither the name of IBM nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+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 OWNER 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.
+*/
+
+/* SPU timer start and alloc library services. */
+#include <spu_timer.h>
+#include "spu_timer_internal.h"
+
+/* The timers. */
+spu_timer_t __spu_timers[SPU_TIMER_NTIMERS] __attribute__ ((aligned (16)));
+
+/* Active timer list. */
+spu_timer_t *__spu_timers_active;
+
+/* Stopped (allocated) timer list. */
+spu_timer_t *__spu_timers_stopped;
+
+/* List of timers being handled. */
+spu_timer_t *__spu_timers_handled;
+
+/* Bitmask of available timers. */
+unsigned __spu_timers_avail =
+ ((1 << (SPU_TIMER_NTIMERS - 1)) + ((1 << (SPU_TIMER_NTIMERS - 1)) - 1));
+
+/* Allocates an SPU interval timer and returns the timer ID. Must be called
+ before starting a timer. interval specifies the expiration interval in
+ timebase units. func specifies the function pointer to expiration handler.
+ Returns the timer ID on success or <0 on Failure:
+ * SPU_TIMER_ERR_NONE_FREE - no free timers to allocate
+ * SPU_TIMER_ERR_INVALID_PARM - invalid parm */
+int
+spu_timer_alloc (int interval, void (*func) (int))
+{
+ unsigned was_enabled;
+ int id;
+ if (interval < MIN_INTVL || interval > MAX_INTVL || func == NULL)
+ return SPU_TIMER_ERR_INVALID_PARM;
+
+ was_enabled = spu_readch (SPU_RdMachStat) & 0x1;
+
+ /* Get id of next available timer. */
+ id = spu_extract ((spu_sub ((unsigned) 31,
+ spu_cntlz (spu_promote
+ (__spu_timers_avail, 0)))), 0);
+
+ /* No timers avail. */
+ if (id == -1)
+ return SPU_TIMER_ERR_NONE_FREE;
+
+ /* Higher order bits represent lower timer ids. */
+ __spu_timers_avail &= ~(1 << (id));
+ id = (SPU_TIMER_NTIMERS - 1) - id;
+
+ /* Initialize timer and put it on stopped list. */
+ (__spu_timers + id)->func = func;
+ (__spu_timers + id)->intvl = interval;
+ (__spu_timers + id)->id = id;
+ (__spu_timers + id)->state = SPU_TIMER_STOPPED;
+
+ spu_idisable ();
+ (__spu_timers + id)->next = __spu_timers_stopped;
+ __spu_timers_stopped = &__spu_timers[id];
+
+ if (__likely (was_enabled))
+ spu_ienable ();
+ return id;
+}
+
+/* External interface for starting a timer. See description of
+ __spu_timer_start(). Returns 0 on success and <0 on failure:
+ * SPU_TIMER_ERR_INVALID_ID - invalid id
+ * SPU_TIMER_ERR_NOCLOCK - clock is off
+ * SPU_TIMER_ERR_NOT_STOPPED - timer not in stopped state */
+int
+spu_timer_start (int id)
+{
+ if (id < 0 || id >= SPU_TIMER_NTIMERS)
+ return SPU_TIMER_ERR_INVALID_ID;
+
+ if (__spu_clock_startcnt == 0)
+ return SPU_TIMER_ERR_NOCLOCK;
+
+ if (__spu_timers[id].state != SPU_TIMER_STOPPED)
+ return SPU_TIMER_ERR_NOT_STOPPED;
+
+ __spu_timer_start (id, 1);
+
+ return 0;
+}