summaryrefslogtreecommitdiffstats
path: root/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND
diff options
context:
space:
mode:
Diffstat (limited to 'Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND')
-rw-r--r--Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/ERRTEST.C86
-rw-r--r--Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/FPESTUB.S96
-rw-r--r--Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/MEMMOVE.C23
-rw-r--r--Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/MEMMOVE.H3
-rw-r--r--Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/MEMTEST.C89
-rw-r--r--Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/README.TXT3
-rw-r--r--Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND.H52
-rw-r--r--Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND.S723
-rw-r--r--Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND1.H56
-rw-r--r--Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND1.S787
-rw-r--r--Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/THUMB/RTSTAND.S819
11 files changed, 2737 insertions, 0 deletions
diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/ERRTEST.C b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/ERRTEST.C
new file mode 100644
index 0000000..1315b8f
--- /dev/null
+++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/ERRTEST.C
@@ -0,0 +1,86 @@
+/*
+ * Standalone Hello World program - tests for presence of the FP
+ * support code and also shows how to interface to the
+ * standalone C kernel's error handler.
+ *
+ * Copyright (C) 1993 Advanced RISC Machines Limited.
+ */
+
+#include "rtstand.h"
+
+extern void __swi(0) put_char(int ch);
+extern void __swi(2) put_string(char *string);
+
+/* First let's roll our own, primitive hex number printer.
+ * Strictly %#.8X format.
+ */
+static void puth(unsigned n) {
+ int j;
+ put_string("0X");
+ for (j = 0; j < 8; ++j) {
+ put_char("0123456789ABCDEF"[n >> 28]);
+ n <<= 4;
+ }
+}
+
+static jmp_buf err_label;
+
+/* This is the function weakly-referenced from the standalone C kernel.
+ * If it exists, it will be called when a run-time error occurs.
+ * If the error is a 'pseudo-error', raised because the error-handler
+ * has been called directly, then the user's register set *r will contain
+ * random values for a1-a4 and ip (r[0-3], r[12]) and r[15] will be
+ * identical to r[14].
+ */
+void __err_handler(__rt_error *e, __rt_registers *r) {
+ put_string("errhandler called: code = ");
+ puth(e->errnum);
+ put_string(": "); put_string(e->errmess); put_string("\r\n");
+ put_string("caller's pc = "); puth(r->r[15]);
+ put_string("\r\nreturning...\r\n");
+#ifdef LONGJMP
+ longjmp(err_label, e->errnum);
+#endif
+}
+
+#ifdef DIVIDE_ERROR
+#define LIMIT 0
+#else
+#define LIMIT 1
+#endif
+
+int main(int argc, char *argv[]) {
+ int rc;
+
+ put_string("(the floating point instruction-set is ");
+ if (!__rt_fpavailable()) put_string("not ");
+ put_string("available)\r\n");
+
+/* Set up the jmp_buffer, and if returning due to longjmp then
+ * goto errlabel
+ */
+ if ((rc = setjmp(err_label)) != 0) goto errlabel;
+
+ if (__rt_fpavailable()) {
+ float a;
+ put_string("Using Floating point, but casting to int ...\r\n");
+ for (a=(float) 10.0;a>=(float) LIMIT;a-=(float) 1.0) {
+ put_string("10000 / "); puth((int) a); put_string(" = ");
+ puth((int) (10000.0/a)); put_string("\r\n");
+ }
+ } else {
+ int a;
+ put_string("Using integer arithmetic ...\r\n");
+ for (a=10;a>=LIMIT;a--) {
+ put_string("10000 / "); puth(a); put_string(" = ");
+ puth(10000/a); put_string("\r\n");
+ }
+ }
+ return 0;
+
+errlabel:
+ put_string("\nReturning from __err_handler() with errnum = ");
+ puth(rc);
+ put_string("\r\n\n");
+ return 0;
+}
diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/FPESTUB.S b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/FPESTUB.S
new file mode 100644
index 0000000..f015a18
--- /dev/null
+++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/FPESTUB.S
@@ -0,0 +1,96 @@
+;;; fpestub.s: library stub for fpe400 (emulator for fp instruction set 3)
+;;;
+;;; Copyright (C) Advanced RISC Machines Ltd., 1993
+
+;;; RCS $Revision: 1.5 $
+;;; Checkin $Date: 1994/01/24 14:19:42 $
+;;; Revising $Author: irickard $
+
+ AREA |FP$$code|, CODE
+
+ IMPORT __rt_trap, WEAK ; from run-time kernel...
+
+; change FPE_ to FPS_ to allow FPA support code to be incorporated in library
+; (there is currently no veneer support for the combined FPE/FPASC)
+ IMPORT FPE_Install
+ IMPORT FPE_DeInstall
+ EXPORT FPE_GenerateError ; to FPE
+
+ EXPORT __fp_initialise ; to client
+ EXPORT __fp_finalise ; to client
+ EXPORT __fp_address_in_emulator ; to client
+
+ IMPORT |FP$$code$$Base|
+ IMPORT |FP$$code$$Limit|
+
+
+; RISCOS SWI names (for use in very_standalone only).
+
+Write0 * 2 + (1:SHL:17)
+NewLine * 3 + (1:SHL:17)
+Exit * &11
+
+;******************************************************************************
+;
+
+
+__fp_initialise
+ B FPE_Install
+
+__fp_finalise
+ B FPE_DeInstall
+
+;******************************************************************************
+;
+; Come here for a floating point exception, such as divide by zero.
+;
+; r0 = error descriptor
+; r1 -> cpu register dump
+;
+
+FPE_GenerateError
+; still in some non-user mode...
+ LDR r2, =|__rt_trap|
+ CMP r2, #0
+ BEQ very_standalone
+ ADD r3, r1, #r13*4
+ LDMIA r3, {r13}^ ; retrieve user's sp
+ NOP
+ MOVS pc, r2 ; to __rt_ in user mode
+
+
+very_standalone
+ [ {CONFIG} = 26
+ TEQP pc, #0 ; to user mode
+ |
+ MSR CPSR_ctl, #&10 ; to user32
+ ]
+ ADD r0, r0, #4 ; ignore the error code
+ SWI Write0 ; write the message
+ SWI NewLine
+ BL |__fp_finalise| ; tidy the ill-instr vector
+ SWI Exit ; and exit
+
+|__fp_address_in_emulator|
+ ; for the benefit of abort handling, determine whether an address
+ ; is within the code of the fp emulator. (Allowing a data abort or
+ ; address exception in a floating-point load or store to be reported
+ ; as occurring at that instruction, rather than somewhere in the code
+ ; of the emulator).
+ [ {CONFIG} = 26
+ BIC r0, r0, #&fc000003 ; remove PSR bits in case
+ ]
+ LDR r1, =|FP$$code$$Base|
+ CMP r0, r1
+ LDRGT r1, =|FP$$code$$Limit|
+ CMPGT r1, r0
+ MOVLE r0, #0
+ MOVGT r0, #1
+ [ {CONFIG} = 26
+ MOVS pc, lr
+ |
+ MOV pc, lr
+ ]
+ LTORG
+
+ END
diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/MEMMOVE.C b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/MEMMOVE.C
new file mode 100644
index 0000000..8039f11
--- /dev/null
+++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/MEMMOVE.C
@@ -0,0 +1,23 @@
+#include "memmove.h"
+
+void *__rt_memmove(void *a, const void *b, size_t n)
+/* copy memory taking care of overlap */
+/* Relies on sizeof(int)=sizeof(void *) and byte addressing.
+ Also that memory does not wrap round for direction test. */
+{
+ /* do it fast if word aligned ... */
+ if ((((int)a | (int)b | (int)n) & 3) == 0)
+ { int *wa,*wb;
+ n >>= 2;
+ if (a < (void *)b)
+ for (wa = (int *)a, wb = (int *)b; n-- > 0;) *wa++ = *wb++;
+ else for (wa = n+(int *)a, wb = n+(int *)b; n-- > 0;) *--wa = *--wb;
+ }
+ else
+ { char *ca,*cb;
+ if (a < (void *)b)
+ for (ca = (char *)a, cb = (char *)b; n-- > 0;) *ca++ = *cb++;
+ else for (ca = n+(char *)a, cb = n+(char *)b; n-- > 0;) *--ca = *--cb;
+ }
+ return a;
+}
diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/MEMMOVE.H b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/MEMMOVE.H
new file mode 100644
index 0000000..480df1b
--- /dev/null
+++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/MEMMOVE.H
@@ -0,0 +1,3 @@
+typedef unsigned int size_t; /* others (e.g. <stdio.h>) define */
+
+extern void *__rt_memmove(void * /*s1*/, const void * /*s2*/, size_t /*n*/);
diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/MEMTEST.C b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/MEMTEST.C
new file mode 100644
index 0000000..46e8f1a
--- /dev/null
+++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/MEMTEST.C
@@ -0,0 +1,89 @@
+/*
+ * Standalone run-time system test.
+ *
+ * This program checks that stack overflow checking works and that it
+ * interacts properly with heap extension.
+ *
+ * Copyright (C) 1991 Advanced RISC Machines Limited.
+ */
+
+#include "rtstand.h"
+
+extern void __swi(0) put_char(int ch);
+extern void __swi(2) put_string(char *string);
+
+/* First, we make a function to claim a large(-ish) stack frame.
+ * Some obfuscation in case the compiler optimises us away...
+ */
+static int stack(int n, int v) {
+ /* claim n KB of stack */
+ int x[256],i;
+
+ if (n > 1) v = stack(n-1, v);
+ for (i = 0; i < 256; ++i) x[i] = v + i;
+ return x[0] + x[255];
+}
+
+/* Now we roll our own decimal output function - strictly %d format...
+ */
+static void puti(int n) {
+ if (n < 0) {
+ put_char('-');
+ n = -n;
+ }
+ if (n > 9) {
+ int n1 = n / 10;
+ n = n % 10;
+ puti(n1);
+ }
+ put_char(n + '0');
+}
+
+/* ...and a hex outputter... strictly %#.8X format.
+ */
+static void puth(unsigned n) {
+ int j;
+ put_string("0X");
+ for (j = 0; j < 8; ++j) {
+ put_char("0123456789ABCDEF"[n >> 28]);
+ n <<= 4;
+ }
+}
+
+/* Finally, we sit in a loop extending the heap and claiming ever bigger
+ * stack franes until something gives. Probably, the heap will give first,
+ * as currently tuned, and the program will announce "memory exhausted".
+ * If you tune it differently, it can be made to fail will a stack overflow
+ * run-time error. Try compiling this -DSTACK_OVERFLOW to provoke it.
+ */
+int main(int argc, char *argv[]) {
+ unsigned size, ask, got, total;
+ void *base;
+
+ put_string("kernel memory management test\r\n");
+
+ size = 4; /* KB */
+ ask = 0;
+ for (total = 0;;) {
+ put_string("force stack to "); puti(size); put_string("KB\r\n");
+ stack(size, 0);
+ put_string("request "); puti(ask); put_string(" words of heap - ");
+ got = __rt_alloc(ask, &base);
+ total += got;
+ put_string("allocate "); puti(got);
+ put_string(" words at "); puth((unsigned)base); put_string("\r\n");
+ if (got < ask) break;
+ ask += got / 2;
+#ifdef STACK_OVERFLOW
+ size *= 2;
+#else
+ size += 4;
+#endif
+ }
+
+ put_string("memory exhausted, ");
+ puti(total); put_string(" words of heap, ");
+ puti(size); put_string("KB of stack\r\n");
+
+ return 0;
+}
diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/README.TXT b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/README.TXT
new file mode 100644
index 0000000..bc81770
--- /dev/null
+++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/README.TXT
@@ -0,0 +1,3 @@
+For details of how to use the files in this directory refer to the ARM
+Programming Techniques, and in particular to the section on
+Deeply Embedded Programming in C.
diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND.H b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND.H
new file mode 100644
index 0000000..1b956ea
--- /dev/null
+++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND.H
@@ -0,0 +1,52 @@
+/*
+ * Standalone C run-time kernel.
+ * Copyright (C) 1991 Advanced RISC Machines Limited.
+ */
+
+#ifndef __rtstand_h
+#define __rtstand_h
+
+
+extern void __rt_exit(int /* code */); /*
+ * Terminate execution; equivalent to returning from main.
+ * NOTE: all other details are determined by your implementation.
+ */
+
+typedef struct {unsigned errnum; char errmess[252];} __rt_error;
+typedef struct {int r[16];} __rt_registers;
+
+extern void __err_handler(__rt_error *, __rt_registers *);
+
+extern int __rt_fpavailable(void);
+/*
+ * Return non-0 iff there is support for the floating-point instruction set.
+ */
+
+extern unsigned __rt_alloc(unsigned /*minwords*/, void ** /*block*/);
+/*
+ * Tries to allocate a block of sensible size >= minwords. Failing that,
+ * it allocates the largest possible block (may have size zero).
+ * Sensible size is determined by your implementation (default: 256 words).
+ * *block is set to a pointer to the start of the allocated block
+ * (NULL if 'a block of size zero' has been allocated).
+ */
+
+#ifdef __JMP_BUF_SIZE
+typedef int jmp_buf[__JMP_BUF_SIZE];
+#else
+typedef int jmp_buf[22]; /* size suitable for the ARM */
+#endif /* an array type suitable for holding the data */
+ /* needed to restore a calling environment. */
+#ifdef __STDC__
+/* setjmp is a macro so that it cannot be used other than directly called. */
+/* NB that ANSI declare that anyone who undefined the setjmp macro or uses */
+/* (or defines) the name setjmp without including this header will get */
+/* what they deserve. NOTE: -pcc mode doesn't allow circular definitions...*/
+#define setjmp(jmp_buf) (setjmp(jmp_buf))
+#endif
+
+extern int setjmp(jmp_buf /*env*/);
+
+extern int longjmp(jmp_buf /*env*/, int /*val*/);
+
+#endif
diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND.S b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND.S
new file mode 100644
index 0000000..325b494
--- /dev/null
+++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND.S
@@ -0,0 +1,723 @@
+; Issue: 0.03/23-Feb-93
+;
+; Purpose: Minimal, standalone, C-library kernel.
+;
+; Copyright (C) 1993 Advanced RISC Machines Limited. All rights reserved.
+;
+; Advanced RISC Machines Limited does not assume any liability arising out
+; of this program or use thereof neither does it convey any licence under
+; its intellectual property rights.
+;
+; Conditions of use:
+;
+; The terms and conditions under which this software is supplied to you and
+; under which you may use it are described in your licence agreement with
+; your supplier.
+;
+;----------------------------------------------------------------------------;
+; ABOUT THIS CODE ;
+; ;
+; This code shows you how to write your own minimal, standalone, run-time ;
+; support system for code compiled by Advanced RISC Machines's C Compiler. ;
+; It can be assembled using Advanced RISC Machines's ARM assembler (armasm) ;
+; or any assembler comaptible with it. ;
+; ;
+; This example code has been written to run under Advanced RISC Machines's ;
+; ARM emulation system (ARMulator). It can also run without modification ;
+; under Acorm Computer's "RISC OS" operating system for its ARM-based ;
+; personal workstations. ;
+; ;
+; In fact, this code depends hardly at all on its target environment and is ;
+; designed to be very easy to adapt to your particular ARM-based system. ;
+; You can expect it to take about a couple of hours to re-target. ;
+; ;
+; Much of the code below is generic to the ARM processor and is completely ;
+; independent of your ARM-based hardware or any operating system kernel that ;
+; may run on it. To get going, you need write only 4 simple fns. ;
+; ;
+; WHAT THIS CODE PROVIDES: ;
+; ;
+; - Example, executable implementations (for the ARMulator) of the few ;
+; simple functions you need to implement to customise this code to your ;
+; environment. These include: ;
+; - setting up the initial stack and heap and calling main (__main) ;
+; - program termination (__rt_exit) ;
+; - determining FP instruction-set availability (__rt_fpavailable) ;
+; ;
+; - Functions to help with heap allocation, stack-limit checking, setjmp ;
+; and longjmp. These may need to be customised for your environment, ;
+; but can almost certainly be used as-is in a first re-targetting. ;
+; ;
+; - Fully 'rolled' divide (and remainder) functions. ;
+; ;
+; WHAT THIS CODE DOES NOT PROVIDE ;
+; ;
+; - Support for handling traps, faults, escapes, exceptions or interrupts. ;
+; ;
+; - A way to print to the debugging channel (use in line SWIs) ;
+; ;
+;----------------------------------------------------------------------------;
+
+;----------------------------------------------------------------------------;
+; The following constant is the Top Of Memory - Adjust this for your system ;
+;----------------------------------------------------------------------------;
+
+TopOfMemory EQU 0x80000 ; 512Kb
+
+;----------------------------------------------------------------------------;
+; Things you may wish to tune, but which you don't need to alter, follow. ;
+;----------------------------------------------------------------------------;
+
+DefaultStackSize EQU 4*1024 ; The stack starts of this big unless
+ ; over-ridden by __root_stack_size.
+
+DefaultStackIncrement EQU 1*1024 ; At each overflow it grows by at
+ ; at least this many bytes.
+
+StackSlop EQU 512 ; sl is kept this far above the real
+ ; stack low-water mark. NOTE: MUST be
+ ; >= 256 or the compiled limit checks
+ ; will be invalidated.
+
+MinHeapIncrement EQU 256 ; Min number of WORDS to extend the
+ ; heap by on calling __rt_alloc.
+
+ GBLL EnsureNoFPSupport
+EnsureNoFPSupport SETL {FALSE} ; If {TRUE} then the availability of
+ ; Floating Point Support is ignored.
+ ; If {FALSE} then FP availability is
+ ; checked for.
+ ; Setting to {TRUE} saves a little
+ ; space.
+
+;----------------------------------------------------------------------------;
+; Symbols defined in other, separately-assembled modules, must be IMPORTed. ;
+; We import them WEAKly so that they need not be defined. ;
+;----------------------------------------------------------------------------;
+
+ IF EnsureNoFPSupport = {FALSE}
+ IMPORT |__fp_initialise|, WEAK
+ IMPORT |__fp_finalise|, WEAK
+ ENDIF
+
+;----------------------------------------------------------------------------;
+; The existence of __fp_initialise (imported WEAKly) indicates that floating ;
+; point support code (or the access stub thereof) has been linked with this ;
+; application. If you wish to load the FP support code separately, you may ;
+; want to define some other mechanism for detecting the presence/absence of ;
+; floating point support. Note that setjmp and longjmp must know whether the ;
+; floating-point instruction set is supported. ;
+; __fp_initialise is called by __main and __fp_finalise is called by _exit. ;
+;----------------------------------------------------------------------------;
+
+ IMPORT |__root_stack_size|, WEAK
+
+;----------------------------------------------------------------------------;
+; If __root_stack_size, also imported WEAKly, exists, the value it addresses ;
+; is used as the initial size of the stack. It can be defined in your C ;
+; program as, e.g. int __root_stack_size = 10000; /* 10KB initial stack */ ;
+;----------------------------------------------------------------------------;
+
+ IMPORT |__err_handler|, WEAK
+
+;----------------------------------------------------------------------------;
+; If __err_handler exists, errors are passed to it; otherwise, we print a ;
+; simple diagnostic message and exit. ;
+;----------------------------------------------------------------------------;
+
+ IMPORT |Image$$RW$$Limit|
+
+;----------------------------------------------------------------------------;
+; Image$$RW$$Limit is a linker-created symbol marking the end of the image. ;
+; Its value is used as the heap base. ;
+;----------------------------------------------------------------------------;
+
+ IMPORT main
+
+;----------------------------------------------------------------------------;
+; The symbol main identifies the C function entered from this code. ;
+;----------------------------------------------------------------------------;
+
+;----------------------------------------------------------------------------;
+; THE MEMORY MODEL ASSUMED BY THIS IMPLEMENTATION ;
+; ;
+; +----------------+ <--- top of memory (high address) ;
+; | Stack space | ;
+; |................| <--- stack pointer (sp) ;
+; | Free stack | ;
+; |................| <--- stack limit pointer (sl) ;
+; +----------------+ <--- stack low-water mark (sl - StackSlop) ;
+; | | ;
+; | Unused memory | ;
+; | | ;
+; +----------------+ <--- top of heap (HeapLimit) ;
+; | | ;
+; | Heap space | ;
+; | | ;
+; +----------------+ <--- top of application (Image$$RW$$Limit) ;
+; | Static data | } ;
+; |................| } the application's memory image ;
+; | Code | } ;
+; +----------------+ <--- application load address ;
+;----------------------------------------------------------------------------;
+
+;----------------------------------------------------------------------------;
+; Now the symbols we define and EXPORT from this this module. ;
+;----------------------------------------------------------------------------;
+; First, symbols identifying the four functions you have to implement to ;
+; make this run-time kernel work on your hardware. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT |__main|
+ EXPORT |__rt_exit|
+ EXPORT |__rt_fpavailable|
+ EXPORT |__rt_trap|
+
+;----------------------------------------------------------------------------;
+; Then some simple support for C heap management. It interacts with stack- ;
+; limit checking but should require no attention in a first re-targetting. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT |__rt_alloc|
+
+;----------------------------------------------------------------------------;
+; Next, optional support for C stack-limit checking. This code should need ;
+; no attention in a first re-targetting. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT |__rt_stkovf_split_small| ; veneer
+ EXPORT |__rt_stkovf_split_big|
+
+;----------------------------------------------------------------------------;
+; Then two C-specific functions which should require no attention in a first ;
+; re-targetting. Note that they depend on __rt_fpavailable. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT |setjmp|
+ EXPORT |longjmp|
+
+;----------------------------------------------------------------------------;
+; And, finally, generic ARM functions, referred to by the C compiler. ;
+; You should not need to alter any of these unless you wish to incorporate ;
+; them in your operating system kernel. See also later comments. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT |__rt_udiv|
+ EXPORT |__rt_udiv10|
+ EXPORT |__rt_sdiv|
+ EXPORT |__rt_sdiv10|
+ EXPORT |__rt_divtest|
+
+;----------------------------------------------------------------------------;
+ AREA |C$$data| ; This module's data area ;
+;----------------------------------------------------------------------------;
+
+HeapLimit
+ DCD |Image$$RW$$Limit| ; initialised by the linker.
+
+;----------------------------------------------------------------------------;
+; This code has to run in but 26-bit ARM modes and 32-bit modes. To allow ;
+; for this, the code is carefully written so that all PSR restoration in ;
+; 26-bit mode is via the following macro. ;
+;----------------------------------------------------------------------------;
+
+ MACRO
+ RET $cond
+ IF {CONFIG} = 26
+ MOV$cond.S pc, lr
+ ELSE
+ MOV$cond pc, lr
+ ENDIF
+ MEND
+
+;----------------------------------------------------------------------------;
+; The following four SWI definitions are specific to ARMulator/RISC OS. ;
+; However, you will need to replace the whole of this following section... ;
+; and all uses of these SWIs should also be replaced. ;
+;----------------------------------------------------------------------------;
+
+WriteC EQU 0 ; Write r0 to error/debug stream.
+Write0 EQU 2 ; Write 0-terminated string pointed
+ ; to by r0 to error/debug stream.
+Exit EQU 17 ; Terminate program execution.
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__main|, CODE, READONLY
+; The code area containing __main, __rt_exit ;
+;----------------------------------------------------------------------------;
+
+ ENTRY ; Define the image entry point.
+
+|__main|
+;
+; This is the initial entry point to the image.
+; Have to establish a stack for C
+; No arguments are passed to main from an embedded application,
+; so argc and argv are set up to 0
+
+ MOV sp, #TopOfMemory ; Initial stack pointer...
+ MOV fp, #0 ; No previous frame, so fp=0
+
+ LDR a3, RootStackSize
+ CMP a3, #0 ; Is RootStackSize defined?
+ LDRNE a3, [a3] ; Yes: use value...
+ CMPNE a3, #DefaultStackSize ; but check caller not being silly.
+ MOVLE a3, #DefaultStackSize ; No/silly: use default size.
+
+ SUB sl, sp, a3 ; stack low-water mark
+ ADD sl, sl, #StackSlop ; sl = LWM + StackSlop
+
+ IF EnsureNoFPSupport = {FALSE}
+ LDR a1, fp_initialise ; initialise FP code if present
+ CMP a1, #0
+ MOVNE lr, pc
+ MOVNE pc, a1
+ ENDIF
+
+ MOV a1, #0 ; set argc to 0
+ MOV a2, #0 ; and argv to NUL
+ BL main ; Call main, falling through to
+ ; exit on return.
+
+|__rt_exit| ; exit
+;
+; void __rt_exit(int code);
+; Terminate execution, optionally setting return code (ignored here).
+; MUST NOT RETURN.
+
+ IF EnsureNoFPSupport = {FALSE}
+ LDR a2, fp_finalise ; finalise FP code if present
+ CMP a2, #0
+ MOVNE lr, pc
+ MOVNE pc, a2
+ ENDIF
+ SWI Exit ; suicide...
+
+RootStackSize
+ DCD |__root_stack_size|
+
+ IF EnsureNoFPSupport = {FALSE}
+fp_initialise
+ DCD |__fp_initialise|
+fp_finalise
+ DCD |__fp_finalise|
+ ENDIF
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__rt_fpavailable|, CODE, READONLY
+; The code area containing __rt_fpavailable ;
+;----------------------------------------------------------------------------;
+
+|__rt_fpavailable|
+;
+; int __rt_fpavailable(); return non-0 if FP support code linked.
+
+ IF EnsureNoFPSupport = {FALSE}
+ LDR a1, fp_initialise
+ ELSE
+ MOV a1, #0
+ ENDIF
+ RET
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__rt_trap|, CODE, READONLY
+; The code area containing __rt_trap ;
+;----------------------------------------------------------------------------;
+; Support for low-level failures - currently stack overflow, divide by 0 and ;
+; floating-point exceptions. If there is a higher level handler, call it; ;
+; otherwise, print a message and exit gracefully. ;
+; ;
+; NOTES ;
+; ;
+; typedef struct { unsigned code; char message[252];} __rt_error; ;
+; typedef struct { unsigned r[16];} __rt_registers; ;
+; ;
+;----------------------------------------------------------------------------;
+
+|__rt_trap|
+;
+; void __rt_trap(__rt_error *e, __rt_registers *r);
+
+ STMFD sp!, {a1} ; save e in case handler returns...
+ LDR ip, err_handler
+ CMP ip, #0
+ MOVNE lr, pc
+ IF {CONFIG} = 26
+ MOVNES pc, ip ; if got a handler, use it and
+ ELSE
+ MOVNE pc, ip ; if got a handler, use it and
+ ENDIF
+ LDMFD sp!, {v1} ; hope not to return...
+
+ ADR a1, RTErrorHead
+ SWI Write0 ; write preamble...
+ ADD a1, v1, #4
+ SWI Write0 ; write error diagnosis
+ ADR a1, RTErrorTail
+ SWI Write0 ; write postlude
+ MOV a1, #255
+ B |__rt_exit| ; and terminate with non-zero exit code
+err_handler
+ DCD |__err_handler|
+
+save_regs_and_trap
+ STMFD sp!, {sp, lr, pc}
+ STMFD sp!, {r0-r12}
+ STR lr, [sp, #4*15] ; caller's pc is my lr
+ MOV a2, sp
+ MOV a1, ip
+ B |__rt_trap|
+
+RTErrorHead
+ DCB 10, 13, "run time error: ", 0
+
+RTErrorTail
+ DCB 10, 13, "program terminated", 10, 13, 10, 13, 0
+
+ ALIGN
+
+;----------------------------------------------------------------------------;
+; YOU SHOULDN'T NEED TO ALTER ANY OF THE FOLLOWING IN A FIRST RETARGETTING. ;
+;----------------------------------------------------------------------------;
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__rt_alloc|, CODE, READONLY
+; The code area containing __rt_alloc ;
+;----------------------------------------------------------------------------;
+; Primitive support for heap memory management. ;
+; ;
+; NOTES ;
+; ;
+; 1/ The allocator embeds knowledge of the memory layout and interacts with ;
+; the stack limit checking code. Here we assume a single address space ;
+; with the stack at the top growing down and the heap below it growing ;
+; up, with a gap (free memory) in between. ;
+; ;
+; 2/ Failure of the stack-limit check is fatal. However, failure of the low- ;
+; level heap allocator is passed back to its caller. ;
+;----------------------------------------------------------------------------;
+
+
+|__rt_alloc| ; alloc
+;
+; unsigned __rt_alloc(unsigned minwords, void **block);
+;
+; This tries to allocate a block of sensible size >= minwords. Failing that,
+; it allocates the largest possible block of sensible size. If it can't do
+; that, it returns zero. *block is set to point to the start of the allocated
+; block (NULL if none has been allocated).
+;
+; NOTE: works in units of WORDS, NOT bytes.
+;
+; In this implementation, sl - StackSlop marks the end of allocatable store.
+
+ CMP a1, #MinHeapIncrement ; round up to at least
+ MOVLT a1, #MinHeapIncrement ; MinHeapIncrement words...
+ LDR a3, HeapLimitAdr
+ LDR a4, [a3] ; current heap high-water mark
+ SUB ip, sl, #StackSlop ; current stack low-water mark
+ CMP a4, ip
+ MOVGE a4, #0 ; no space, *block = NULL
+ STR a4, [a2]
+ MOVGE a1, #0 ; no space, return 0
+ ADD a4, a4, a1, LSL #2 ; proposed new heap limit
+ CMP a4, ip
+ SUBGT a2, a4, ip ; byte overlap, >= 0 by earlier code
+ SUBGT a1, a1, a2, LSR #2 ; reduce word request
+ MOVGT a4, ip ; new high-water = stack low-water
+ STR a4, [a3]
+ RET
+HeapLimitAdr
+ DCD HeapLimit
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__rt_stkovf|, CODE, READONLY
+; The code area containing __rt_stkovf_* ;
+;----------------------------------------------------------------------------;
+; C stack-limit checking support. ;
+; ;
+; NOTES ;
+; ;
+; 1/ Stack-limit-checking is optional - you can compile your C code without ;
+; stack-limit checks (#pragma nocheck_stack or cc -zps0). However, the ;
+; cost of the check is (very) small and the value sometimes considerable. ;
+; ;
+; 2/ The limit check embeds knowledge of the memory layout and interacts ;
+; with the primitive memory management supported by __rt_alloc. Here, we ;
+; assume a single address space with the stack at the top growing down ;
+; and the heap below it growing up, with a gap (free memory) in between. ;
+; ;
+; 3/ Failure of the stack-limit check is fatal. However, failure of the low- ;
+; level heap allocator is passed back to its caller. ;
+; ;
+; 4/ This implementation never reduces the size of the stack. It simply ;
+; moves the low-water mark monatonically downwards. It is easy to do ;
+; better, but, of course, it takes more code and is more target-specific. ;
+;----------------------------------------------------------------------------;
+
+|__rt_stkovf_split_small| ; stkovf_split_small_frame ;
+;
+; Enter here when a C function with frame size <= 256 bytes underflows
+; the stack low-water mark + StackSlop (sl). The stack space required has
+; already been claimed by decrementing sp, so we set the proposed sp (ip)
+; to the actual sp and fall into the big-frame case.
+
+ MOV ip, sp ; fall into big-frame case with size of 0.
+
+|__rt_stkovf_split_big| ; stkovf_split_big_frame ;
+;
+; Enter here when a C function with frame size > 256 bytes would underflow
+; the stack low-water mark + StackSlop (sl). No stack space has been claimed
+; but the proposed new stack pointer is in ip.
+
+ SUB ip, sp, ip ; frame size required...
+ CMP ip, #DefaultStackIncrement ; rounded up to at least
+ MOVLT ip, #DefaultStackIncrement ; the default increment
+
+ SUB sl, sl, ip
+ SUB sl, sl, #StackSlop ; new stack low-water mark
+
+ LDR ip, HeapLimitAdr ; check doesn't collide with
+ LDR ip, [ip] ; the heap.
+ CMP ip, sl
+ ADD sl, sl, #StackSlop ; restore safety margin
+ BGT stackoverflow
+ RET ; and return if OK...
+
+stackoverflow
+ ADR ip, StackOverflowError
+ B save_regs_and_trap
+
+StackOverflowError
+ DCD 3
+ DCB "stack overflow", 0
+ ALIGN
+
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__jmp|, CODE, READONLY
+; The code area containing setjmp, longjmp ;
+;----------------------------------------------------------------------------;
+; Setjmp and longjmp support. ;
+; ;
+; NOTES ;
+; ;
+; 1/ Specific to C and not implementable in C. ;
+; ;
+; 2/ Interacts with stack management and possibly with memory management. ;
+; e.g. on a chunked stack, longjmp must de-allocate jumped-over chunks. ;
+; ;
+; 3/ Must know whether the floating-point instruction-set is supported! ;
+; (DEPENDS ON __rt_fpavailable to discover this). ;
+; ;
+;----------------------------------------------------------------------------;
+
+ MAP 0 ; This structure maps the jmp_buf
+sj_v1 # 4 ; data type assumed by the C compiler.
+sj_v2 # 4 ; First, space to save the v-registers...
+sj_v3 # 4
+sj_v4 # 4
+sj_v5 # 4
+sj_v6 # 4
+sj_sl # 4 ; then the frame registers sl, fp, sp (ap),
+sj_fp # 4 ; and pc/lr...
+sj_ap # 4
+sj_pc # 4
+sj_f4 # 3*4 ; and finally the floating-point reisters,
+sj_f5 # 3*4 ; used only if floating point support is
+sj_f6 # 3*4 ; available.
+sj_f7 # 3*4
+
+
+|setjmp| ; setjmp
+;
+; int setjmp(jmp_buf env);
+; Saves everything that might count as a register variable in 'env'.
+
+ STMIA a1!, {v1-v6, sl, fp, sp, lr}
+ MOV v6, a1 ; v6 safe in env - use to point past
+ ; saved lr (at 1st FP slot)
+ BL |__rt_fpavailable|
+ CMP a1, #0
+ BEQ setjmp_return ; no fp
+ STFE f4, [v6, #sj_f4-sj_f4]
+ STFE f5, [v6, #sj_f5-sj_f4]
+ STFE f6, [v6, #sj_f6-sj_f4]
+ STFE f7, [v6, #sj_f7-sj_f4]
+ MOV a1, #0 ; must return 0 from a direct call
+setjmp_return
+ LDMDB v6, {v6, sl, fp, sp, lr}
+ RET
+
+|longjmp| ; longjmp ;
+; int longjmp(jmp_buf env, int val);
+
+ MOV v1, a1 ; save env ptr over call to fpavailable
+ MOVS v6, a2 ; ensure non-0 return value...
+ MOVEQ v6, #1 ; (must NOT return 0 on longjmp(env, 0))
+ BL |__rt_fpavailable|
+ CMP a1, #0
+ BEQ longjmp_return
+ LDFE f7, [v1, #sj_f7]
+ LDFE f6, [v1, #sj_f6]
+ LDFE f5, [v1, #sj_f5]
+ LDFE f4, [v1, #sj_f4]
+longjmp_return
+ MOV a1, v6
+ LDMIA v1, {v1-v6, sl, fp, sp, lr}
+ RET
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__divide|, CODE, READONLY
+; The code area containing __rt_sdiv, __rt_udiv, __rt_sdiv_10, __rt_udiv10 ;
+;----------------------------------------------------------------------------;
+; GENERIC ARM FUNCTIONS - divide and remainder. ;
+; ;
+; NOTES ;
+; ;
+; 1/ You may wish to make these functions part of your O/S kernel, replacing ;
+; the implementations here by branches to the relevant entry addresses. ;
+; ;
+; 2/ Each divide function is a div-rem function, returning the quotient in ;
+; r0 and the remainder in r1. Thus (r0, r1) -> (r0/r1, r0%r1). This is ;
+; understood by the C compiler. ;
+; ;
+; 3/ Because of its importance in many applications, divide by 10 is treated ;
+; as a special case. The C compiler recognises divide by 10 and generates ;
+; calls to __rt_{u,s}div10, as appropriate. ;
+; ;
+; 4/ Each of the implementations below has been coded with smallness as a ;
+; higher priority than speed. Unrolling the loops will allow faster ;
+; execution, but will produce much larger code. If the speed of divides ;
+; is critical then unrolled versions can be extracted from the ARM ANSI C ;
+; Library. ;
+; ;
+;----------------------------------------------------------------------------;
+
+; div_core is used by __rt_sdiv and __rt_udiv, and corrupts a3, a4 and ip
+div_core
+ CMP a3, a4
+ MOVHI a4, a4, ASL #1
+ BHI div_core
+div_core2
+ CMP a2, a4
+ ADC ip, ip, ip
+ SUBHS a2, a2, a4
+ CMP a1, a4
+ MOVLO a4, a4, LSR #1
+ BLO div_core2
+ MOV a1, ip
+ RET
+
+; Signed divide of a2 by a1: returns quotient in a1, remainder in a2
+; Quotient is truncated (rounded towards zero).
+; Sign of remainder = sign of dividend.
+; Destroys a3, a4 and ip
+; Negates dividend and divisor, then does an unsigned divide; signs
+; get sorted out again at the end.
+
+|__rt_sdiv|
+ MOVS a3, a1
+ BEQ dividebyzero ; ip now unwanted
+
+ RSBMI a1, a1, #0 ; absolute value of divisor
+ EOR a3, a3, a2
+ ANDS ip, a2, #&80000000
+ ORR a3, ip, a3, LSR #1
+ STMFD sp!,{a3,lr}
+ ; saved a3:
+ ; bit 31 sign of dividend (= sign of remainder)
+ ; bit 30 sign of dividend EOR sign of divisor (= sign of quotient)
+ RSBNE a2, a2, #0 ; absolute value of dividend
+
+ MOV a3, a2
+ MOV a4, a1
+ MOV ip, #0
+ BL div_core
+ LDMFD sp!,{a3}
+ MOVS a3, a3, ASL #1
+ RSBMI a1, a1, #0
+ RSBCS a2, a2, #0
+ IF {CONFIG} = 26
+ LDMFD sp!,{pc}^
+ ELSE
+ LDMFD sp!,{pc}
+ ENDIF
+
+; Unsigned divide of a2 by a1: returns quotient in a1, remainder in a2
+; Destroys a4, ip and r5
+
+|__rt_udiv|
+ MOVS a4, a1
+ BEQ dividebyzero
+
+ MOV ip, #0
+ MOV a3, #&80000000
+ CMP a2, a3
+ MOVLO a3, a2
+ B div_core
+
+;
+; Fast unsigned divide by 10: dividend in a1, divisor in a2.
+; Returns quotient in a1, remainder in a2.
+; Also destroys a3.
+;
+; Calculate x / 10 as (x * 2**32/10) / 2**32.
+; That is, we calculate the most significant word of the double-length
+; product. In fact, we calculate an approximation which may be 1 off
+; because we've ignored a carry from the least significant word we didn't
+; calculate. We correct for this by insisting that the remainder < 10
+; and by incrementing the quotient if it isn't.
+
+|__rt_udiv10| ; udiv10 ;
+ MOV a2, a1
+ MOV a1, a1, LSR #1
+ ADD a1, a1, a1, LSR #1
+ ADD a1, a1, a1, LSR #4
+ ADD a1, a1, a1, LSR #8
+ ADD a1, a1, a1, LSR #16
+ MOV a1, a1, LSR #3
+ ADD a3, a1, a1, ASL #2
+ SUB a2, a2, a3, ASL #1
+ CMP a2, #10
+ ADDGE a1, a1, #1
+ SUBGE a2, a2, #10
+ RET
+
+;
+; Fast signed divide by 10: dividend in a1, divisor in a2.
+; Returns quotient in a1, remainder in a2.
+; Also destroys a3 and a4.
+; Quotient is truncated (rounded towards zero).
+; Make use of __rt_udiv10
+
+|__rt_sdiv10| ; sdiv10 ;
+ MOV ip, lr
+ MOVS a4, a1
+ RSBMI a1, a1, #0
+ BL __rt_udiv10
+ CMP a4, #0
+ RSBMI a1, a1, #0
+ RSBMI a2, a2, #0
+ IF {CONFIG} = 26
+ MOVS pc, ip
+ ELSE
+ MOV pc, ip
+ ENDIF
+
+;
+; Test for division by zero (used when division is voided).
+
+|__rt_divtest| ; divtest ;
+ CMPS a1, #0
+ RET NE
+dividebyzero
+ ADR ip, DivideByZeroError
+ B save_regs_and_trap
+
+DivideByZeroError
+ DCD 1
+ DCB "divide by 0", 0
+ ALIGN
+
+ END
diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND1.H b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND1.H
new file mode 100644
index 0000000..0366f05
--- /dev/null
+++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND1.H
@@ -0,0 +1,56 @@
+/*
+ * Standalone C run-time kernel.
+ * Copyright (C) 1991 Advanced RISC Machines Limited.
+ */
+
+#ifndef __rtstand_h
+#define __rtstand_h
+
+
+extern void __rt_exit(int /* code */); /*
+ * Terminate execution; equivalent to returning from main.
+ * NOTE: all other details are determined by your implementation.
+ */
+
+typedef struct {unsigned errnum; char errmess[252];} __rt_error;
+typedef struct {int r[16];} __rt_registers;
+
+extern void __err_handler(__rt_error *, __rt_registers *);
+
+extern int __rt_fpavailable(void);
+/*
+ * Return non-0 iff there is support for the floating-point instruction set.
+ */
+
+extern unsigned __rt_alloc(unsigned /*minwords*/, void ** /*block*/);
+/*
+ * Tries to allocate a block of sensible size >= minwords. Failing that,
+ * it allocates the largest possible block (may have size zero).
+ * Sensible size is determined by your implementation (default: 256 words).
+ * *block is set to a pointer to the start of the allocated block
+ * (NULL if 'a block of size zero' has been allocated).
+ */
+
+#ifdef __JMP_BUF_SIZE
+typedef int jmp_buf[__JMP_BUF_SIZE];
+#else
+typedef int jmp_buf[22]; /* size suitable for the ARM */
+#endif /* an array type suitable for holding the data */
+ /* needed to restore a calling environment. */
+#ifdef __STDC__
+/* setjmp is a macro so that it cannot be used other than directly called. */
+/* NB that ANSI declare that anyone who undefined the setjmp macro or uses */
+/* (or defines) the name setjmp without including this header will get */
+/* what they deserve. NOTE: -pcc mode doesn't allow circular definitions...*/
+#define setjmp(jmp_buf) (setjmp(jmp_buf))
+#endif
+
+extern int setjmp(jmp_buf /*env*/);
+
+extern int longjmp(jmp_buf /*env*/, int /*val*/);
+
+typedef unsigned int size_t; /* others (e.g. <stdio.h>) define */
+
+extern void *__rt_memmove(void * /*s1*/, const void * /*s2*/, size_t /*n*/);
+
+#endif
diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND1.S b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND1.S
new file mode 100644
index 0000000..7d85dfa
--- /dev/null
+++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/RTSTAND1.S
@@ -0,0 +1,787 @@
+; Issue: 0.03/23-Feb-93
+;
+; Purpose: Minimal, standalone, C-library kernel.
+;
+; Copyright (C) 1993 Advanced RISC Machines Limited. All rights reserved.
+;
+; Advanced RISC Machines Limited does not assume any liability arising out
+; of this program or use thereof neither does it convey any licence under
+; its intellectual property rights.
+;
+; Conditions of use:
+;
+; The terms and conditions under which this software is supplied to you and
+; under which you may use it are described in your licence agreement with
+; your supplier.
+;
+;----------------------------------------------------------------------------;
+; ABOUT THIS CODE ;
+; ;
+; This code shows you how to write your own minimal, standalone, run-time ;
+; support system for code compiled by Advanced RISC Machines's C Compiler. ;
+; It can be assembled using Advanced RISC Machines's ARM assembler (armasm) ;
+; or any assembler comaptible with it. ;
+; ;
+; This example code has been written to run under Advanced RISC Machines's ;
+; ARM emulation system (ARMulator). It can also run without modification ;
+; under Acorm Computer's "RISC OS" operating system for its ARM-based ;
+; personal workstations. ;
+; ;
+; In fact, this code depends hardly at all on its target environment and is ;
+; designed to be very easy to adapt to your particular ARM-based system. ;
+; You can expect it to take about a couple of hours to re-target. ;
+; ;
+; Much of the code below is generic to the ARM processor and is completely ;
+; independent of your ARM-based hardware or any operating system kernel that ;
+; may run on it. To get going, you need write only 4 simple fns. ;
+; ;
+; WHAT THIS CODE PROVIDES: ;
+; ;
+; - Example, executable implementations (for the ARMulator) of the few ;
+; simple functions you need to implement to customise this code to your ;
+; environment. These include: ;
+; - setting up the initial stack and heap and calling main (__main) ;
+; - program termination (__rt_exit) ;
+; - determining FP instruction-set availability (__rt_fpavailable) ;
+; ;
+; - Functions to help with heap allocation, stack-limit checking, setjmp ;
+; and longjmp. These may need to be customised for your environment, ;
+; but can almost certainly be used as-is in a first re-targetting. ;
+; ;
+; - Fully 'rolled' divide (and remainder) functions. ;
+; ;
+; WHAT THIS CODE DOES NOT PROVIDE ;
+; ;
+; - Support for handling traps, faults, escapes, exceptions or interrupts. ;
+; ;
+; - A way to print to the debugging channel (use in line SWIs) ;
+; ;
+;----------------------------------------------------------------------------;
+
+;----------------------------------------------------------------------------;
+; The following constant is the Top Of Memory - Adjust this for your system ;
+;----------------------------------------------------------------------------;
+
+TopOfMemory EQU 0x80000 ; 512Kb
+
+;----------------------------------------------------------------------------;
+; Things you may wish to tune, but which you don't need to alter, follow. ;
+;----------------------------------------------------------------------------;
+
+DefaultStackSize EQU 4*1024 ; The stack starts of this big unless
+ ; over-ridden by __root_stack_size.
+
+DefaultStackIncrement EQU 1*1024 ; At each overflow it grows by at
+ ; at least this many bytes.
+
+StackSlop EQU 512 ; sl is kept this far above the real
+ ; stack low-water mark. NOTE: MUST be
+ ; >= 256 or the compiled limit checks
+ ; will be invalidated.
+
+MinHeapIncrement EQU 256 ; Min number of WORDS to extend the
+ ; heap by on calling __rt_alloc.
+
+ GBLL EnsureNoFPSupport
+EnsureNoFPSupport SETL {FALSE} ; If {TRUE} then the availability of
+ ; Floating Point Support is ignored.
+ ; If {FALSE} then FP availability is
+ ; checked for.
+ ; Setting to {TRUE} saves a little
+ ; space.
+
+;----------------------------------------------------------------------------;
+; Symbols defined in other, separately-assembled modules, must be IMPORTed. ;
+; We import them WEAKly so that they need not be defined. ;
+;----------------------------------------------------------------------------;
+
+ IF EnsureNoFPSupport = {FALSE}
+ IMPORT |__fp_initialise|, WEAK
+ IMPORT |__fp_finalise|, WEAK
+ ENDIF
+
+;----------------------------------------------------------------------------;
+; The existence of __fp_initialise (imported WEAKly) indicates that floating ;
+; point support code (or the access stub thereof) has been linked with this ;
+; application. If you wish to load the FP support code separately, you may ;
+; want to define some other mechanism for detecting the presence/absence of ;
+; floating point support. Note that setjmp and longjmp must know whether the ;
+; floating-point instruction set is supported. ;
+; __fp_initialise is called by __main and __fp_finalise is called by _exit. ;
+;----------------------------------------------------------------------------;
+
+ IMPORT |__root_stack_size|, WEAK
+
+;----------------------------------------------------------------------------;
+; If __root_stack_size, also imported WEAKly, exists, the value it addresses ;
+; is used as the initial size of the stack. It can be defined in your C ;
+; program as, e.g. int __root_stack_size = 10000; /* 10KB initial stack */ ;
+;----------------------------------------------------------------------------;
+
+ IMPORT |__err_handler|, WEAK
+
+;----------------------------------------------------------------------------;
+; If __err_handler exists, errors are passed to it; otherwise, we print a ;
+; simple diagnostic message and exit. ;
+;----------------------------------------------------------------------------;
+
+ IMPORT |Image$$RW$$Limit|
+
+;----------------------------------------------------------------------------;
+; Image$$RW$$Limit is a linker-created symbol marking the end of the image. ;
+; Its value is used as the heap base. ;
+;----------------------------------------------------------------------------;
+
+ IMPORT main
+
+;----------------------------------------------------------------------------;
+; The symbol main identifies the C function entered from this code. ;
+;----------------------------------------------------------------------------;
+
+;----------------------------------------------------------------------------;
+; THE MEMORY MODEL ASSUMED BY THIS IMPLEMENTATION ;
+; ;
+; +----------------+ <--- top of memory (high address) ;
+; | Stack space | ;
+; |................| <--- stack pointer (sp) ;
+; | Free stack | ;
+; |................| <--- stack limit pointer (sl) ;
+; +----------------+ <--- stack low-water mark (sl - StackSlop) ;
+; | | ;
+; | Unused memory | ;
+; | | ;
+; +----------------+ <--- top of heap (HeapLimit) ;
+; | | ;
+; | Heap space | ;
+; | | ;
+; +----------------+ <--- top of application (Image$$RW$$Limit) ;
+; | Static data | } ;
+; |................| } the application's memory image ;
+; | Code | } ;
+; +----------------+ <--- application load address ;
+;----------------------------------------------------------------------------;
+
+;----------------------------------------------------------------------------;
+; Now the symbols we define and EXPORT from this this module. ;
+;----------------------------------------------------------------------------;
+; First, symbols identifying the four functions you have to implement to ;
+; make this run-time kernel work on your hardware. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT |__main|
+ EXPORT |__rt_exit|
+ EXPORT |__rt_fpavailable|
+ EXPORT |__rt_trap|
+
+;----------------------------------------------------------------------------;
+; Then some simple support for C heap management. It interacts with stack- ;
+; limit checking but should require no attention in a first re-targetting. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT |__rt_alloc|
+
+;----------------------------------------------------------------------------;
+; Next, optional support for C stack-limit checking. This code should need ;
+; no attention in a first re-targetting. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT |__rt_stkovf_split_small| ; veneer
+ EXPORT |__rt_stkovf_split_big|
+
+;----------------------------------------------------------------------------;
+; Then two C-specific functions which should require no attention in a first ;
+; re-targetting. Note that they depend on __rt_fpavailable. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT |setjmp|
+ EXPORT |longjmp|
+
+;----------------------------------------------------------------------------;
+; And, finally, generic ARM functions, referred to by the C compiler. ;
+; You should not need to alter any of these unless you wish to incorporate ;
+; them in your operating system kernel. See also later comments. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT |__rt_udiv|
+ EXPORT |__rt_udiv10|
+ EXPORT |__rt_sdiv|
+ EXPORT |__rt_sdiv10|
+ EXPORT |__rt_divtest|
+
+;----------------------------------------------------------------------------;
+ AREA |C$$data| ; This module's data area ;
+;----------------------------------------------------------------------------;
+
+HeapLimit
+ DCD |Image$$RW$$Limit| ; initialised by the linker.
+
+;----------------------------------------------------------------------------;
+; This code has to run in but 26-bit ARM modes and 32-bit modes. To allow ;
+; for this, the code is carefully written so that all PSR restoration in ;
+; 26-bit mode is via the following macro. ;
+;----------------------------------------------------------------------------;
+
+ MACRO
+ RET $cond
+ IF {CONFIG} = 26
+ MOV$cond.S pc, lr
+ ELSE
+ MOV$cond pc, lr
+ ENDIF
+ MEND
+
+;----------------------------------------------------------------------------;
+; The following four SWI definitions are specific to ARMulator/RISC OS. ;
+; However, you will need to replace the whole of this following section... ;
+; and all uses of these SWIs should also be replaced. ;
+;----------------------------------------------------------------------------;
+
+WriteC EQU 0 ; Write r0 to error/debug stream.
+Write0 EQU 2 ; Write 0-terminated string pointed
+ ; to by r0 to error/debug stream.
+Exit EQU 17 ; Terminate program execution.
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__main|, CODE, READONLY
+; The code area containing __main, __rt_exit ;
+;----------------------------------------------------------------------------;
+
+ ENTRY ; Define the image entry point.
+
+|__main|
+;
+; This is the initial entry point to the image.
+; Have to establish a stack for C
+; No arguments are passed to main from an embedded application,
+; so argc and argv are set up to 0
+
+ MOV sp, #TopOfMemory ; Initial stack pointer...
+ MOV fp, #0 ; No previous frame, so fp=0
+
+ LDR a3, RootStackSize
+ CMP a3, #0 ; Is RootStackSize defined?
+ LDRNE a3, [a3] ; Yes: use value...
+ CMPNE a3, #DefaultStackSize ; but check caller not being silly.
+ MOVLE a3, #DefaultStackSize ; No/silly: use default size.
+
+ SUB sl, sp, a3 ; stack low-water mark
+ ADD sl, sl, #StackSlop ; sl = LWM + StackSlop
+
+ IF EnsureNoFPSupport = {FALSE}
+ LDR a1, fp_initialise ; initialise FP code if present
+ CMP a1, #0
+ MOVNE lr, pc
+ MOVNE pc, a1
+ ENDIF
+
+ MOV a1, #0 ; set argc to 0
+ MOV a2, #0 ; and argv to NUL
+ BL main ; Call main, falling through to
+ ; exit on return.
+
+|__rt_exit| ; exit
+;
+; void __rt_exit(int code);
+; Terminate execution, optionally setting return code (ignored here).
+; MUST NOT RETURN.
+
+ IF EnsureNoFPSupport = {FALSE}
+ LDR a2, fp_finalise ; finalise FP code if present
+ CMP a2, #0
+ MOVNE lr, pc
+ MOVNE pc, a2
+ ENDIF
+ SWI Exit ; suicide...
+
+RootStackSize
+ DCD |__root_stack_size|
+
+ IF EnsureNoFPSupport = {FALSE}
+fp_initialise
+ DCD |__fp_initialise|
+fp_finalise
+ DCD |__fp_finalise|
+ ENDIF
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__rt_fpavailable|, CODE, READONLY
+; The code area containing __rt_fpavailable ;
+;----------------------------------------------------------------------------;
+
+|__rt_fpavailable|
+;
+; int __rt_fpavailable(); return non-0 if FP support code linked.
+
+ IF EnsureNoFPSupport = {FALSE}
+ LDR a1, fp_initialise
+ ELSE
+ MOV a1, #0
+ ENDIF
+ RET
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__rt_trap|, CODE, READONLY
+; The code area containing __rt_trap ;
+;----------------------------------------------------------------------------;
+; Support for low-level failures - currently stack overflow, divide by 0 and ;
+; floating-point exceptions. If there is a higher level handler, call it; ;
+; otherwise, print a message and exit gracefully. ;
+; ;
+; NOTES ;
+; ;
+; typedef struct { unsigned code; char message[252];} __rt_error; ;
+; typedef struct { unsigned r[16];} __rt_registers; ;
+; ;
+;----------------------------------------------------------------------------;
+
+|__rt_trap|
+;
+; void __rt_trap(__rt_error *e, __rt_registers *r);
+
+ STMFD sp!, {a1} ; save e in case handler returns...
+ LDR ip, err_handler
+ CMP ip, #0
+ MOVNE lr, pc
+ IF {CONFIG} = 26
+ MOVNES pc, ip ; if got a handler, use it and
+ ELSE
+ MOVNE pc, ip ; if got a handler, use it and
+ ENDIF
+ LDMFD sp!, {v1} ; hope not to return...
+
+ ADR a1, RTErrorHead
+ SWI Write0 ; write preamble...
+ ADD a1, v1, #4
+ SWI Write0 ; write error diagnosis
+ ADR a1, RTErrorTail
+ SWI Write0 ; write postlude
+ MOV a1, #255
+ B |__rt_exit| ; and terminate with non-zero exit code
+err_handler
+ DCD |__err_handler|
+
+save_regs_and_trap
+ STMFD sp!, {sp, lr, pc}
+ STMFD sp!, {r0-r12}
+ STR lr, [sp, #4*15] ; caller's pc is my lr
+ MOV a2, sp
+ MOV a1, ip
+ B |__rt_trap|
+
+RTErrorHead
+ DCB 10, 13, "run time error: ", 0
+
+RTErrorTail
+ DCB 10, 13, "program terminated", 10, 13, 10, 13, 0
+
+ ALIGN
+
+;----------------------------------------------------------------------------;
+; YOU SHOULDN'T NEED TO ALTER ANY OF THE FOLLOWING IN A FIRST RETARGETTING. ;
+;----------------------------------------------------------------------------;
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__rt_alloc|, CODE, READONLY
+; The code area containing __rt_alloc ;
+;----------------------------------------------------------------------------;
+; Primitive support for heap memory management. ;
+; ;
+; NOTES ;
+; ;
+; 1/ The allocator embeds knowledge of the memory layout and interacts with ;
+; the stack limit checking code. Here we assume a single address space ;
+; with the stack at the top growing down and the heap below it growing ;
+; up, with a gap (free memory) in between. ;
+; ;
+; 2/ Failure of the stack-limit check is fatal. However, failure of the low- ;
+; level heap allocator is passed back to its caller. ;
+;----------------------------------------------------------------------------;
+
+
+|__rt_alloc| ; alloc
+;
+; unsigned __rt_alloc(unsigned minwords, void **block);
+;
+; This tries to allocate a block of sensible size >= minwords. Failing that,
+; it allocates the largest possible block of sensible size. If it can't do
+; that, it returns zero. *block is set to point to the start of the allocated
+; block (NULL if none has been allocated).
+;
+; NOTE: works in units of WORDS, NOT bytes.
+;
+; In this implementation, sl - StackSlop marks the end of allocatable store.
+
+ CMP a1, #MinHeapIncrement ; round up to at least
+ MOVLT a1, #MinHeapIncrement ; MinHeapIncrement words...
+ LDR a3, HeapLimitAdr
+ LDR a4, [a3] ; current heap high-water mark
+ SUB ip, sl, #StackSlop ; current stack low-water mark
+ CMP a4, ip
+ MOVGE a4, #0 ; no space, *block = NULL
+ STR a4, [a2]
+ MOVGE a1, #0 ; no space, return 0
+ ADD a4, a4, a1, LSL #2 ; proposed new heap limit
+ CMP a4, ip
+ SUBGT a2, a4, ip ; byte overlap, >= 0 by earlier code
+ SUBGT a1, a1, a2, LSR #2 ; reduce word request
+ MOVGT a4, ip ; new high-water = stack low-water
+ STR a4, [a3]
+ RET
+HeapLimitAdr
+ DCD HeapLimit
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__rt_stkovf|, CODE, READONLY
+; The code area containing __rt_stkovf_* ;
+;----------------------------------------------------------------------------;
+; C stack-limit checking support. ;
+; ;
+; NOTES ;
+; ;
+; 1/ Stack-limit-checking is optional - you can compile your C code without ;
+; stack-limit checks (#pragma nocheck_stack or cc -zps0). However, the ;
+; cost of the check is (very) small and the value sometimes considerable. ;
+; ;
+; 2/ The limit check embeds knowledge of the memory layout and interacts ;
+; with the primitive memory management supported by __rt_alloc. Here, we ;
+; assume a single address space with the stack at the top growing down ;
+; and the heap below it growing up, with a gap (free memory) in between. ;
+; ;
+; 3/ Failure of the stack-limit check is fatal. However, failure of the low- ;
+; level heap allocator is passed back to its caller. ;
+; ;
+; 4/ This implementation never reduces the size of the stack. It simply ;
+; moves the low-water mark monatonically downwards. It is easy to do ;
+; better, but, of course, it takes more code and is more target-specific. ;
+;----------------------------------------------------------------------------;
+
+|__rt_stkovf_split_small| ; stkovf_split_small_frame ;
+;
+; Enter here when a C function with frame size <= 256 bytes underflows
+; the stack low-water mark + StackSlop (sl). The stack space required has
+; already been claimed by decrementing sp, so we set the proposed sp (ip)
+; to the actual sp and fall into the big-frame case.
+
+ MOV ip, sp ; fall into big-frame case with size of 0.
+
+|__rt_stkovf_split_big| ; stkovf_split_big_frame ;
+;
+; Enter here when a C function with frame size > 256 bytes would underflow
+; the stack low-water mark + StackSlop (sl). No stack space has been claimed
+; but the proposed new stack pointer is in ip.
+
+ SUB ip, sp, ip ; frame size required...
+ CMP ip, #DefaultStackIncrement ; rounded up to at least
+ MOVLT ip, #DefaultStackIncrement ; the default increment
+
+ SUB sl, sl, ip
+ SUB sl, sl, #StackSlop ; new stack low-water mark
+
+ LDR ip, HeapLimitAdr ; check doesn't collide with
+ LDR ip, [ip] ; the heap.
+ CMP ip, sl
+ ADD sl, sl, #StackSlop ; restore safety margin
+ BGT stackoverflow
+ RET ; and return if OK...
+
+stackoverflow
+ ADR ip, StackOverflowError
+ B save_regs_and_trap
+
+StackOverflowError
+ DCD 3
+ DCB "stack overflow", 0
+ ALIGN
+
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__jmp|, CODE, READONLY
+; The code area containing setjmp, longjmp ;
+;----------------------------------------------------------------------------;
+; Setjmp and longjmp support. ;
+; ;
+; NOTES ;
+; ;
+; 1/ Specific to C and not implementable in C. ;
+; ;
+; 2/ Interacts with stack management and possibly with memory management. ;
+; e.g. on a chunked stack, longjmp must de-allocate jumped-over chunks. ;
+; ;
+; 3/ Must know whether the floating-point instruction-set is supported! ;
+; (DEPENDS ON __rt_fpavailable to discover this). ;
+; ;
+;----------------------------------------------------------------------------;
+
+ MAP 0 ; This structure maps the jmp_buf
+sj_v1 # 4 ; data type assumed by the C compiler.
+sj_v2 # 4 ; First, space to save the v-registers...
+sj_v3 # 4
+sj_v4 # 4
+sj_v5 # 4
+sj_v6 # 4
+sj_sl # 4 ; then the frame registers sl, fp, sp (ap),
+sj_fp # 4 ; and pc/lr...
+sj_ap # 4
+sj_pc # 4
+sj_f4 # 3*4 ; and finally the floating-point reisters,
+sj_f5 # 3*4 ; used only if floating point support is
+sj_f6 # 3*4 ; available.
+sj_f7 # 3*4
+
+
+|setjmp| ; setjmp
+;
+; int setjmp(jmp_buf env);
+; Saves everything that might count as a register variable in 'env'.
+
+ STMIA a1!, {v1-v6, sl, fp, sp, lr}
+ MOV v6, a1 ; v6 safe in env - use to point past
+ ; saved lr (at 1st FP slot)
+ BL |__rt_fpavailable|
+ CMP a1, #0
+ BEQ setjmp_return ; no fp
+ STFE f4, [v6, #sj_f4-sj_f4]
+ STFE f5, [v6, #sj_f5-sj_f4]
+ STFE f6, [v6, #sj_f6-sj_f4]
+ STFE f7, [v6, #sj_f7-sj_f4]
+ MOV a1, #0 ; must return 0 from a direct call
+setjmp_return
+ LDMDB v6, {v6, sl, fp, sp, lr}
+ RET
+
+|longjmp| ; longjmp ;
+; int longjmp(jmp_buf env, int val);
+
+ MOV v1, a1 ; save env ptr over call to fpavailable
+ MOVS v6, a2 ; ensure non-0 return value...
+ MOVEQ v6, #1 ; (must NOT return 0 on longjmp(env, 0))
+ BL |__rt_fpavailable|
+ CMP a1, #0
+ BEQ longjmp_return
+ LDFE f7, [v1, #sj_f7]
+ LDFE f6, [v1, #sj_f6]
+ LDFE f5, [v1, #sj_f5]
+ LDFE f4, [v1, #sj_f4]
+longjmp_return
+ MOV a1, v6
+ LDMIA v1, {v1-v6, sl, fp, sp, lr}
+ RET
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__divide|, CODE, READONLY
+; The code area containing __rt_sdiv, __rt_udiv, __rt_sdiv_10, __rt_udiv10 ;
+;----------------------------------------------------------------------------;
+; GENERIC ARM FUNCTIONS - divide and remainder. ;
+; ;
+; NOTES ;
+; ;
+; 1/ You may wish to make these functions part of your O/S kernel, replacing ;
+; the implementations here by branches to the relevant entry addresses. ;
+; ;
+; 2/ Each divide function is a div-rem function, returning the quotient in ;
+; r0 and the remainder in r1. Thus (r0, r1) -> (r0/r1, r0%r1). This is ;
+; understood by the C compiler. ;
+; ;
+; 3/ Because of its importance in many applications, divide by 10 is treated ;
+; as a special case. The C compiler recognises divide by 10 and generates ;
+; calls to __rt_{u,s}div10, as appropriate. ;
+; ;
+; 4/ Each of the implementations below has been coded with smallness as a ;
+; higher priority than speed. Unrolling the loops will allow faster ;
+; execution, but will produce much larger code. If the speed of divides ;
+; is critical then unrolled versions can be extracted from the ARM ANSI C ;
+; Library. ;
+; ;
+;----------------------------------------------------------------------------;
+
+; div_core is used by __rt_sdiv and __rt_udiv, and corrupts a3, a4 and ip
+div_core
+ CMP a3, a4
+ MOVHI a4, a4, ASL #1
+ BHI div_core
+div_core2
+ CMP a2, a4
+ ADC ip, ip, ip
+ SUBHS a2, a2, a4
+ CMP a1, a4
+ MOVLO a4, a4, LSR #1
+ BLO div_core2
+ MOV a1, ip
+ RET
+
+; Signed divide of a2 by a1: returns quotient in a1, remainder in a2
+; Quotient is truncated (rounded towards zero).
+; Sign of remainder = sign of dividend.
+; Destroys a3, a4 and ip
+; Negates dividend and divisor, then does an unsigned divide; signs
+; get sorted out again at the end.
+
+|__rt_sdiv|
+ MOVS a3, a1
+ BEQ dividebyzero ; ip now unwanted
+
+ RSBMI a1, a1, #0 ; absolute value of divisor
+ EOR a3, a3, a2
+ ANDS ip, a2, #&80000000
+ ORR a3, ip, a3, LSR #1
+ STMFD sp!,{a3,lr}
+ ; saved a3:
+ ; bit 31 sign of dividend (= sign of remainder)
+ ; bit 30 sign of dividend EOR sign of divisor (= sign of quotient)
+ RSBNE a2, a2, #0 ; absolute value of dividend
+
+ MOV a3, a2
+ MOV a4, a1
+ MOV ip, #0
+ BL div_core
+ LDMFD sp!,{a3}
+ MOVS a3, a3, ASL #1
+ RSBMI a1, a1, #0
+ RSBCS a2, a2, #0
+ IF {CONFIG} = 26
+ LDMFD sp!,{pc}^
+ ELSE
+ LDMFD sp!,{pc}
+ ENDIF
+
+; Unsigned divide of a2 by a1: returns quotient in a1, remainder in a2
+; Destroys a4, ip and r5
+
+|__rt_udiv|
+ MOVS a4, a1
+ BEQ dividebyzero
+
+ MOV ip, #0
+ MOV a3, #&80000000
+ CMP a2, a3
+ MOVLO a3, a2
+ B div_core
+
+;
+; Fast unsigned divide by 10: dividend in a1, divisor in a2.
+; Returns quotient in a1, remainder in a2.
+; Also destroys a3.
+;
+; Calculate x / 10 as (x * 2**32/10) / 2**32.
+; That is, we calculate the most significant word of the double-length
+; product. In fact, we calculate an approximation which may be 1 off
+; because we've ignored a carry from the least significant word we didn't
+; calculate. We correct for this by insisting that the remainder < 10
+; and by incrementing the quotient if it isn't.
+
+|__rt_udiv10| ; udiv10 ;
+ MOV a2, a1
+ MOV a1, a1, LSR #1
+ ADD a1, a1, a1, LSR #1
+ ADD a1, a1, a1, LSR #4
+ ADD a1, a1, a1, LSR #8
+ ADD a1, a1, a1, LSR #16
+ MOV a1, a1, LSR #3
+ ADD a3, a1, a1, ASL #2
+ SUB a2, a2, a3, ASL #1
+ CMP a2, #10
+ ADDGE a1, a1, #1
+ SUBGE a2, a2, #10
+ RET
+
+;
+; Fast signed divide by 10: dividend in a1, divisor in a2.
+; Returns quotient in a1, remainder in a2.
+; Also destroys a3 and a4.
+; Quotient is truncated (rounded towards zero).
+; Make use of __rt_udiv10
+
+|__rt_sdiv10| ; sdiv10 ;
+ MOV ip, lr
+ MOVS a4, a1
+ RSBMI a1, a1, #0
+ BL __rt_udiv10
+ CMP a4, #0
+ RSBMI a1, a1, #0
+ RSBMI a2, a2, #0
+ IF {CONFIG} = 26
+ MOVS pc, ip
+ ELSE
+ MOV pc, ip
+ ENDIF
+
+;
+; Test for division by zero (used when division is voided).
+
+|__rt_divtest| ; divtest ;
+ CMPS a1, #0
+ RET NE
+dividebyzero
+ ADR ip, DivideByZeroError
+ B save_regs_and_trap
+
+DivideByZeroError
+ DCD 1
+ DCB "divide by 0", 0
+ ALIGN
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__rt_memmove|, CODE, READONLY
+; The code area containing __rt_memmove() extracted from the ARM C Library ;
+; Note that as this was produced using armcc -apcs 3/32bit it is only ;
+; intended for use in 32 bit modes ;
+;----------------------------------------------------------------------------;
+
+ EXPORT |__rt_memmove|
+|__rt_memmove|
+ ORR a4,a1,a2
+ ORR a4,a4,a3
+ ANDS a4,a4,#3
+ BNE |L000064.J4.__rt_memmove|
+ MOV a3,a3,LSR #2
+ CMP a1,a2
+ MOVLT a4,a1
+ BLT |L000034.J9.__rt_memmove|
+ ADD a4,a1,a3,LSL #2
+ ADD a2,a2,a3,LSL #2
+ B |L000050.J13.__rt_memmove|
+|L00002c.J8.__rt_memmove|
+ LDR ip,[a2],#4
+ STR ip,[a4],#4
+|L000034.J9.__rt_memmove|
+ MOV ip,a3
+ SUB a3,a3,#1
+ CMP ip,#0
+ BHI |L00002c.J8.__rt_memmove|
+ MOV pc,lr
+|L000048.J12.__rt_memmove|
+ LDR ip,[a2,#-4]!
+ STR ip,[a4,#-4]!
+|L000050.J13.__rt_memmove|
+ MOV ip,a3
+ SUB a3,a3,#1
+ CMP ip,#0
+ BHI |L000048.J12.__rt_memmove|
+ MOV pc,lr
+|L000064.J4.__rt_memmove|
+ CMP a1,a2
+ MOVLT a4,a1
+ BLT |L000084.J19.__rt_memmove|
+ ADD a4,a1,a3
+ ADD a2,a2,a3
+ B |L0000a0.J23.__rt_memmove|
+|L00007c.J18.__rt_memmove|
+ LDRB ip,[a2],#1
+ STRB ip,[a4],#1
+|L000084.J19.__rt_memmove|
+ MOV ip,a3
+ SUB a3,a3,#1
+ CMP ip,#0
+ BHI |L00007c.J18.__rt_memmove|
+ MOV pc,lr
+|L000098.J22.__rt_memmove|
+ LDRB ip,[a2,#-1]!
+ STRB ip,[a4,#-1]!
+|L0000a0.J23.__rt_memmove|
+ MOV ip,a3
+ SUB a3,a3,#1
+ CMP ip,#0
+ BHI |L000098.J22.__rt_memmove|
+ MOV pc,lr
+
+ END
diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/THUMB/RTSTAND.S b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/THUMB/RTSTAND.S
new file mode 100644
index 0000000..605926f
--- /dev/null
+++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/CLSTAND/THUMB/RTSTAND.S
@@ -0,0 +1,819 @@
+; Issue: 1.00/19-Jan-95
+;
+; Purpose: Minimal, standalone, C-library kernel for Thumb
+;
+; Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
+;
+; Advanced RISC Machines Limited does not assume any liability arising out
+; of this program or use thereof neither does it convey any licence under
+; its intellectual property rights.
+;
+; Conditions of use:
+;
+; The terms and conditions under which this software is supplied to you and
+; under which you may use it are described in your licence agreement with
+; your supplier.
+;
+;----------------------------------------------------------------------------;
+; ABOUT THIS CODE ;
+; ;
+; This code shows you how to write your own minimal, standalone, Thumb ;
+; run-time support system for code compiled by Advanced RISC Machines's ;
+; Thumb C Compiler. It can be assembled using Advanced RISC Machines's Thumb ;
+; assembler. ;
+; ;
+; This code may be used to build a ROM image. It may also be run under ;
+; Advanced RISC Machines's ARM emulation system (ARMulator). ;
+; ;
+; In fact, this code depends hardly at all on its target environment and is ;
+; designed to be very easy to adapt to your particular ARM-based system. ;
+; ;
+; Much of the code below is generic to the ARM processor and is completely ;
+; independent of your ARM-based hardware or any operating system kernel that ;
+; may run on it. To get going, you need write only 4 simple fns. ;
+; ;
+; WHAT THIS CODE PROVIDES: ;
+; ;
+; - Example, executable implementations of the few ;
+; simple functions you need to implement to customise this code to your ;
+; environment. These include: ;
+; - setting up the initial stack and heap and calling main (__main) ;
+; - program termination (__rt_exit) ;
+; ;
+; - Functions to help with heap allocation, stack-limit checking, setjmp ;
+; and longjmp. These may need to be customised for your environment, ;
+; but can almost certainly be used as-is in a first re-targetting. ;
+; ;
+; - Fully 'rolled' divide (and remainder) functions. ;
+; ;
+; WHAT THIS CODE DOES NOT PROVIDE ;
+; ;
+; - Support for handling traps, faults, escapes, exceptions or interrupts. ;
+; ;
+; - A way to print to the debugging channel (use in line SWIs) ;
+; ;
+;----------------------------------------------------------------------------;
+
+;----------------------------------------------------------------------------;
+; The following constant is the Top Of RAM - Adjust this for your system ;
+;----------------------------------------------------------------------------;
+
+TopOfMemory EQU 0x80000 ; 512Kb
+
+;----------------------------------------------------------------------------;
+; Things you may wish to tune, but which you don't need to alter, follow. ;
+;----------------------------------------------------------------------------;
+
+DefaultStackSize EQU 4*1024 ; The stack starts of this big unless
+ ; over-ridden by __root_stack_size.
+
+DefaultStackIncrement EQU 1*1024 ; At each overflow it grows by at
+ ; at least this many bytes.
+
+StackSlop EQU 512 ; sl is kept this far above the real
+ ; stack low-water mark. NOTE: MUST be
+ ; >= 256 or the compiled limit checks
+ ; will be invalidated.
+
+MinHeapIncrement EQU 256 ; Min number of WORDS to extend the
+ ; heap by on calling __rt_alloc.
+
+;----------------------------------------------------------------------------;
+; Symbols defined in other, separately-assembled modules, must be IMPORTed. ;
+; We import them WEAKly so that they need not be defined. ;
+;----------------------------------------------------------------------------;
+
+ IMPORT __root_stack_size, WEAK
+
+;----------------------------------------------------------------------------;
+; If __root_stack_size, also imported WEAKly, exists, the value it addresses ;
+; is used as the initial size of the stack. It can be defined in your C ;
+; program as, e.g. int __root_stack_size = 10000; /* 10KB initial stack */ ;
+;----------------------------------------------------------------------------;
+
+ IMPORT __err_handler, WEAK
+
+;----------------------------------------------------------------------------;
+; If __err_handler exists, errors are passed to it; otherwise, we print a ;
+; simple diagnostic message and exit. ;
+;----------------------------------------------------------------------------;
+
+ IMPORT |Image$$RO$$Base|
+ IMPORT |Image$$RO$$Limit|
+ IMPORT |Image$$RW$$Base|
+ IMPORT |Image$$RW$$Limit|
+ IMPORT |Image$$ZI$$Base|
+ IMPORT |Image$$ZI$$Limit|
+
+;----------------------------------------------------------------------------;
+; The above symbols are created by the linker to define various sections in ;
+; the ROM/RAM image. ;
+; ;
+; Image$$RO$$Base defines the code (ROM) base address ;
+; Image$$RO$$Limit defines the code limit and the start of a section of ;
+; data initialisation values which are copied to RAM ;
+; in __main below before main is called. ;
+; Image$$RW$$Base defines the data (RAM) base address ;
+; Image$$RW$$Limit defines the data end address ;
+; Image$$ZI$$Base defines the base of a section to be initialised with 0s ;
+; Image$$ZI$$Limit defines the end of the region to be initialised with 0s ;
+; (must be the same as Image$$RW$$Limit in this model) ;
+;----------------------------------------------------------------------------;
+
+ IMPORT main
+
+;----------------------------------------------------------------------------;
+; The symbol main identifies the C function entered from this code. ;
+;----------------------------------------------------------------------------;
+
+;----------------------------------------------------------------------------;
+; THE MEMORY MODEL ASSUMED BY THIS IMPLEMENTATION ;
+; ;
+; RAM ;
+; ;
+; +------------------+ <--- top of memory (high address) ;
+; | Stack space | ;
+; |..................| <--- stack pointer (sp) ;
+; | Free stack | ;
+; |..................| <--- stack limit pointer (sl) ;
+; +------------------+ <--- stack low-water mark (sl - StackSlop) ;
+; | | ;
+; | Unused memory | ;
+; | | ;
+; +------------------+ <--- top of heap (HeapLimit) ;
+; | | ;
+; | Heap space | ;
+; | | ;
+; +------------------+ <--- top of fixed data (Image$$RW$$Limit) ;
+; | Zero init data | (=Image$$ZI$$Limit) ;
+; +------------------+ <--- top of initialised (Image$$ZI$$Base) ;
+; | Initialised data | data ;
+; +------------------+ <--- Data base address (Image$$RW$$Base) ;
+; ;
+; ROM ;
+; ;
+; +------------------+ <--- Top of ROM image ;
+; | Initial values | } Copied to "Initialised data" section in RAM ;
+; | for Init data | } on statup in __main below ;
+; +------------------+ <--- End of code (Image$$RO$$Limit) ;
+; | Code | ;
+; +------------------+ <--- Code base address (Image$$RO$$Base) ;
+;----------------------------------------------------------------------------;
+
+;----------------------------------------------------------------------------;
+; Now the symbols we define and EXPORT from this module. ;
+;----------------------------------------------------------------------------;
+; First, symbols identifying the four functions you have to implement to ;
+; make this run-time kernel work on your hardware. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT __main
+ EXPORT __rt_exit
+ EXPORT __rt_trap
+
+;----------------------------------------------------------------------------;
+; Then some simple support for C heap management. It interacts with stack- ;
+; limit checking but should require no attention in a first re-targetting. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT __rt_alloc
+
+;----------------------------------------------------------------------------;
+; Next, optional support for C stack-limit checking. This code should need ;
+; no attention in a first re-targetting. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT __16__rt_stkovf_split_small ; veneer
+ EXPORT __16__rt_stkovf_split_big
+
+;----------------------------------------------------------------------------;
+; Then two C-specific functions which should require no attention in a first ;
+; re-targetting. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT setjmp
+ EXPORT longjmp
+
+;----------------------------------------------------------------------------;
+; And, finally, generic ARM functions, referred to by the C compiler. ;
+; You should not need to alter any of these unless you wish to incorporate ;
+; them in your operating system kernel. See also later comments. ;
+;----------------------------------------------------------------------------;
+
+ EXPORT __16__rt_udiv
+ EXPORT __16__rt_udiv10
+ EXPORT __16__rt_sdiv
+ EXPORT __16__rt_sdiv10
+ EXPORT __16__rt_divtest
+
+;----------------------------------------------------------------------------;
+ AREA |C$$data| ; This module's data area ;
+;----------------------------------------------------------------------------;
+
+HeapLimit
+ DCD |Image$$RW$$Limit| ; initialised by the linker.
+
+;----------------------------------------------------------------------------;
+; Macro to return from a function ;
+; We use the BX instruction below rather than MOV pc, lr so that the return ;
+; will work correctly if we are called from ARM state ;
+;----------------------------------------------------------------------------;
+
+ MACRO
+ RET
+ BX lr
+ MEND
+
+;----------------------------------------------------------------------------;
+; The following four SWI definitions are specific to ARMulator/RISC OS. ;
+; However, you will need to replace the whole of this following section... ;
+; and all uses of these SWIs should also be replaced. ;
+;----------------------------------------------------------------------------;
+
+WriteC EQU 0 ; Write r0 to error/debug stream.
+Write0 EQU 2 ; Write 0-terminated string pointed
+ ; to by r0 to error/debug stream.
+Exit EQU 17 ; Terminate program execution.
+
+ CODE16
+
+TBit EQU 1 ; Bit to set in register to enter
+ ; Thumb state with BX <reg>
+
+;----------------------------------------------------------------------------;
+; Use area name "!!!" so this area is placed first as AREAs are sorted by
+; area name.
+ AREA |!!!|, CODE, READONLY, INTERWORK
+; The code area containing __main, __rt_exit ;
+;----------------------------------------------------------------------------;
+
+ ENTRY ; Define the image entry point.
+
+__main
+ CODE32 ; Entered in ARM state presumeably
+ ADR lr, __main_16+TBit
+ BX lr
+ CODE16
+__main_16
+;
+; This is the initial entry point to the image.
+; Have to establish a stack for C
+; No arguments are passed to main from an embedded application,
+; so argc and argv are set up to 0
+
+ LDR r0, =TopOfMemory ; Set up initial stack pointer
+ MOV sp, r0
+
+ MOV r0, #0
+ MOV fp, r0 ; No previous frame, so fp=0
+
+ LDR r0, =DefaultStackSize
+ LDR r1, =__root_stack_size
+ CMP r1, #0 ; Is RootStackSize defined?
+ BEQ %F0 ; No => Use default
+ LDR r1, [r1] ; Yes => Get value
+ CMP r1, r0 ; But check value >= DefaultStackSize
+ BCC %F0 ; if >= use default in r0.
+ MOV r0, r1
+0
+ MOV r1, sp
+ SUB r1, r0 ; stack low limit
+ LDR r0, =StackSlop
+ ADD r1, r0 ; plus a bit spare
+ MOV sl, r1
+
+; Now initialise the data segment by copying the initial values from ROM
+; to RAM and by clearing the zero init segment to 0.
+
+ LDR r0, =|Image$$RO$$Limit| ; Get pointer to ROM initial values
+ LDR r1, =|Image$$RW$$Base| ; And RAM data segment
+ LDR r3, =|Image$$ZI$$Base| ; Zero init base = top of initialised segment
+ CMP r0, r1 ; Check that they are different, (they may be
+ BEQ %F3 ; the same if the image is running in RAM)
+ B %F2
+1
+ LDMIA r0!, {r2} ; Copy the initialising data over
+ STMIA r1!, {r2}
+2 CMP r1, r3
+ BCC %B1
+3
+ LDR r1, =|Image$$ZI$$Limit| ; Top of area to be zero initialised
+ MOV r2, #0
+ B %F5
+
+4 STMIA r3!, {r2} ; Clear out zero init segment
+5 CMP r3, r1
+ BCC %B4
+
+ MOV r0, #0 ; set argc to 0
+ MOV r1, #0 ; and argv to NUL
+ BL main ; Call main, falling through to
+ ; exit on return.
+
+__rt_exit ; exit
+;
+; void __rt_exit(int code);
+; Terminate execution, optionally setting return code (ignored here).
+; MUST NOT RETURN.
+
+ SWI Exit ; suicide...
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__rt_trap|, CODE, READONLY
+; The code area containing __rt_trap ;
+;----------------------------------------------------------------------------;
+; Support for low-level failures - currently stack overflow and divide by 0. ;
+; If there is a higher level handler, call it otherwise, print a message and ;
+; exit gracefully. ;
+; ;
+; NOTES ;
+; ;
+; typedef struct { unsigned code; char message[252];} __rt_error; ;
+; typedef struct { unsigned r[16];} __rt_registers; ;
+; ;
+;----------------------------------------------------------------------------;
+
+__rt_trap
+;
+; void __rt_trap(__rt_error *e, __rt_registers *r);
+
+ PUSH {r0} ; save e in case handler returns...
+ LDR r3, =__err_handler
+ CMP r3, #0
+ BEQ %F0
+
+ BL call_via_r3 ; Call the routine pointed to by R3
+ ; Note: BL sets bit 0 of LR so return will
+ ; be to Thumb state. This is why we use this
+ ; rather than the sequence
+ ; MOV lr, pc
+ ; BX r3
+ ; which may return to ARM state!
+
+0
+ ADR r0, RTErrorHead ; No handler, or handler returned
+ SWI Write0 ; write preamble...
+ POP {r0}
+ ADD r0, #4
+ SWI Write0 ; write error diagnosis
+ ADR r0, RTErrorTail
+ SWI Write0 ; write postlude
+ MOV a1, #255
+ BL __rt_exit ; and terminate with non-zero exit code
+
+call_via_r3
+ BX r3
+
+; SP has already been decremented by 16 * 4 and R0..R7 saved.
+; IP points to the error description
+; R7 contains the LR register which has been destroyed as a BL was required
+; to get here.
+save_regs_and_trap
+ MOV ip, r0
+ MOV r0, r8
+ MOV r1, r9
+ MOV r2, r10
+ MOV r3, r11
+ MOV r4, r12
+ ADD r5, sp, #16*4 ; Take account of previous SP adjustment
+ ADD r6, sp, #8*4 ; Pointer to hi reg save area
+ STMIA r6!, {r0-r5, r7}
+ STR r7, [sp, #15*4] ; Save my pc as callers lr
+ MOV a2, sp
+ MOV a1, ip
+ B __rt_trap
+
+ ALIGN
+RTErrorHead
+ DCB 10, 13, "run time error: ", 0
+
+ ALIGN
+RTErrorTail
+ DCB 10, 13, "program terminated", 10, 13, 10, 13, 0
+
+ ALIGN
+
+;----------------------------------------------------------------------------;
+; YOU SHOULDN'T NEED TO ALTER ANY OF THE FOLLOWING IN A FIRST RETARGETTING. ;
+;----------------------------------------------------------------------------;
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__rt_alloc|, CODE, READONLY
+; The code area containing __rt_alloc ;
+;----------------------------------------------------------------------------;
+; Primitive support for heap memory management. ;
+; ;
+; NOTES ;
+; ;
+; 1/ The allocator embeds knowledge of the memory layout and interacts with ;
+; the stack limit checking code. Here we assume a single address space ;
+; with the stack at the top growing down and the heap below it growing ;
+; up, with a gap (free memory) in between. ;
+; ;
+; 2/ Failure of the stack-limit check is fatal. However, failure of the low- ;
+; level heap allocator is passed back to its caller. ;
+;----------------------------------------------------------------------------;
+
+
+__rt_alloc ; alloc
+;
+; unsigned __rt_alloc(unsigned minwords, void **block);
+;
+; This tries to allocate a block of sensible size >= minwords. Failing that,
+; it allocates the largest possible block of sensible size. If it can't do
+; that, it returns zero. *block is set to point to the start of the allocated
+; block (NULL if none has been allocated).
+;
+; NOTE: works in units of WORDS, NOT bytes.
+;
+; In this implementation, sl - StackSlop marks the end of allocatable store.
+
+ LDR r2, =MinHeapIncrement
+ CMP r0, r2 ; round up to at least
+ BGE %F0
+ MOV r0, r2 ; MinHeapIncrement words...
+0
+ MOV ip, sl
+ LDR r2, =-StackSlop
+ ADD ip, r2 ; current stack low-water mark
+ LDR r2, =HeapLimit
+ LDR r3, [r2] ; current heap high-water mark
+ CMP r3, ip
+ BLE %F1
+ MOV r3, #0 ; no space, *block = NULL
+ MOV r0, #0 ; no space, return 0
+1
+ STR r3, [r1]
+ LSL r0, #2 ; Convert size request to bytes
+ ADD r3, r0 ; proposed new heap limit
+ CMP r3, ip
+ BLE %F2
+ ADD r0, ip ; Reduce size request by amount
+ SUB r0, r3 ; of overlap
+ MOV r3, ip ; new high-water = stack low-water
+2
+ STR r3, [r2]
+ LSR r0, #2 ; Convert return size to words
+ RET
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__rt_stkovf|, CODE, READONLY
+; The code area containing __rt_stkovf_* ;
+
+ [ :LNOT::DEF:STACK_EXTENSION
+ GBLL STACK_EXTENSION
+STACK_EXTENSION SETL {FALSE}
+ ]
+;----------------------------------------------------------------------------;
+; C stack-limit checking support. ;
+; ;
+; NOTES ;
+; ;
+; 1/ This code is only called if stack checking is enabled with the ;
+; -apcs 3/swst option on the Thumb compiler. Typically you will only do ;
+; this when debugging. ;
+; ;
+; 2/ The code may be configured to either perform automatic stack extension ;
+; or to generate an error on stack overflow. By default it is set up to ;
+; generate an error. To change this to extend the stack uncomment the ;
+; following line. ;
+; ;
+;STACK_EXTENSION SETL {TRUE} ;
+; ;
+; 3/ The stack extension embeds knowledge of the memory layout and interacts ;
+; with the primitive memory management supported by __rt_alloc. Here, we ;
+; assume a single address space with the stack at the top growing down ;
+; and the heap below it growing up, with a gap (free memory) in between. ;
+; ;
+; 4/ Failure of the stack-limit check is fatal. However, failure of the low- ;
+; level heap allocator is passed back to its caller. ;
+; ;
+; 5/ This implementation of stack extension never reduces the size of the ;
+; stack. It simply moves the low-water mark downwards. It is easy to do ;
+; better, but, of course, it takes more code and is more target-specific. ;
+;----------------------------------------------------------------------------;
+
+__16__rt_stkovf_split_small
+;
+; Enter here when a C function with frame size <= 256 bytes underflows
+; the stack low-water mark + StackSlop (sl). The stack space required has
+; already been claimed by decrementing sp, so we set the proposed sp (ip)
+; to the actual sp and fall into the big-frame case.
+
+ [ STACK_EXTENSION
+ MOV ip, sp ; fall into big-frame case with size of 0.
+ ]
+
+__16__rt_stkovf_split_big
+;
+; Enter here when a C function with frame size > 256 bytes would underflow
+; the stack low-water mark + StackSlop (sl). No stack space has been claimed
+; but the proposed new stack pointer is in ip.
+
+ [ STACK_EXTENSION
+ PUSH {r0,r1}
+ ADD r0, sp, #8 ; get original sp
+ MOV r1, ip
+ SUB r0, r1 ; frame size required...
+ LDR r1, =DefaultStackIncrement
+ CMP r0, r1 ; rounded up to at least
+ BGE %F0
+ MOV r0, r1 ; the default increment
+0
+ MOV r1, sl
+ SUB r1, r0
+ LDR r0, =StackSlop
+ SUB r1, r0 ; new stack low-water mark
+ MOV sl, r1
+
+ LDR r1, =HeapLimit
+ LDR r1, [r1] ; check doesn't collide with
+ CMP r1, sl ; the heap.
+ ADD sl, r0 ; restore safety margin
+ ; (preserves CC)
+
+ POP {r0, r1}
+ BGT stackoverflow
+ RET ; and return if OK...
+
+ ]
+stackoverflow
+ SUB sp, sp, #8*4 ; Room for R8..R15
+ PUSH {r0-r7}
+ MOV r7, lr
+ ADR r0, StackOverflowError
+ BL save_regs_and_trap
+
+ ALIGN
+StackOverflowError
+ DCD 3
+ DCB "stack overflow", 0
+ ALIGN
+
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__jmp|, CODE, READONLY
+; The code area containing setjmp, longjmp ;
+;----------------------------------------------------------------------------;
+; Setjmp and longjmp support. ;
+; ;
+; NOTES ;
+; ;
+; 1/ Specific to C and not implementable in C. ;
+; ;
+; 2/ Interacts with stack management and possibly with memory management. ;
+; e.g. on a chunked stack, longjmp must de-allocate jumped-over chunks. ;
+; ;
+;----------------------------------------------------------------------------;
+
+ MAP 0 ; This structure maps the jmp_buf
+sj_v1 # 4 ; data type assumed by the C compiler.
+sj_v2 # 4 ; First, space to save the v-registers...
+sj_v3 # 4
+sj_v4 # 4
+sj_v5 # 4
+sj_v6 # 4
+sj_sl # 4 ; then the frame registers sl, fp, sp (ap),
+sj_fp # 4 ; and pc/lr...
+sj_ap # 4
+sj_pc # 4
+
+
+setjmp
+;
+; int setjmp(jmp_buf env);
+; Saves everything that might count as a register variable in 'env'.
+
+ STMIA a1!, {r4-r7}
+ MOV r0, r8
+ MOV r1, r9
+ MOV r2, sl
+ MOV r3, fp
+ STMIA a1!, {r0-r3}
+ MOV r0, sp
+ MOV r1, lr
+ STMIA a1!, {r0-r1}
+ MOV a1, #0 ; must return 0 from a direct call
+ RET
+
+longjmp
+; int longjmp(jmp_buf env, int val);
+
+ ADD r0, #4*4
+ LDMIA r0!, {r2-r7} ; Restore r8 .. lr
+ MOV r8, r2
+ MOV r9, r3
+ MOV sl, r4
+ MOV fp, r5
+ MOV sp, r6
+ MOV lr, r7
+ SUB r0, #10*4
+ LDMIA r0!, {r4-r7} ; Restore v1..v4
+ MOV r0, r1
+ BNE %F0
+ MOV r0, #1 ; Must not return 0
+0
+ RET
+
+;----------------------------------------------------------------------------;
+ AREA |C$$code$$__divide|, CODE, READONLY
+; The code area containing __rt_sdiv, __rt_udiv, __rt_sdiv_10, __rt_udiv10 ;
+;----------------------------------------------------------------------------;
+; GENERIC ARM FUNCTIONS - divide and remainder. ;
+; ;
+; NOTES ;
+; ;
+; 1/ You may wish to make these functions part of your O/S kernel, replacing ;
+; the implementations here by branches to the relevant entry addresses. ;
+; ;
+; 2/ Each divide function is a div-rem function, returning the quotient in ;
+; r0 and the remainder in r1. Thus (r0, r1) -> (r0/r1, r0%r1). This is ;
+; understood by the C compiler. ;
+; ;
+; 3/ Because of its importance in many applications, divide by 10 is treated ;
+; as a special case. The C compiler recognises divide by 10 and generates ;
+; calls to __rt_{u,s}div10, as appropriate. ;
+; ;
+; 4/ Each of the implementations below has been coded with smallness as a ;
+; higher priority than speed. Unrolling the loops will allow faster ;
+; execution, but will produce much larger code. If the speed of divides ;
+; is critical then unrolled versions can be extracted from the ARM ANSI C ;
+; Library. ;
+; ;
+;----------------------------------------------------------------------------;
+
+; Signed divide of a2 by a1: returns quotient in a1, remainder in a2
+; Quotient is truncated (rounded towards zero).
+; Sign of remainder = sign of dividend.
+; Destroys a3, a4 and ip
+; Negates dividend and divisor, then does an unsigned divide; signs
+; get sorted out again at the end.
+
+__16__rt_sdiv
+ ASR a4, a2, #31
+ EOR a2, a4
+ SUB a2, a4
+
+ ASR a3, a1, #31
+ EOR a1, a3
+ SUB a1, a3
+
+ BEQ dividebyzero
+
+ PUSH {a3, a4} ; Save so we can look at signs later on
+
+ LSR a4, a2, #1
+ MOV a3, a1
+
+s_loop CMP a3, a4
+ BNLS %FT0
+ LSL a3, #1
+0 BLO s_loop
+
+ MOV a4, #0
+ B %FT0
+s_loop2 LSR a3, #1
+0 CMP a2, a3
+ ADC a4, a4
+ CMP a2, a3
+ BCC %FT0
+ SUB a2, a3
+0
+ CMP a3, a1
+ BNE s_loop2
+ MOV a1, a4
+
+ POP {a3, a4}
+
+ EOR a3, a4
+ EOR a1, a3
+ SUB a1, a3
+
+ EOR a2, a4
+ SUB a2, a4
+
+ RET
+
+; Unsigned divide of a2 by a1: returns quotient in a1, remainder in a2
+; Destroys a4, ip and r5
+
+__16__rt_udiv
+ LSR a4, a2, #1
+ MOV a3, a1
+ BEQ dividebyzero
+
+u_loop CMP a3, a4
+ BNLS %FT0
+ LSL a3, #1
+0 BLO u_loop
+
+ MOV a4, #0
+ B %FT0
+u_loop2 LSR a3, #1
+0 CMP a2, a3
+ ADC a4, a4
+ CMP a2, a3
+ BCC %FT0
+ SUB a2, a3
+0
+ CMP a3, a1
+ BNE u_loop2
+ MOV a1, a4
+
+ RET
+
+;
+; Fast unsigned divide by 10: dividend in a1, divisor in a2.
+; Returns quotient in a1, remainder in a2.
+; Also destroys a3.
+;
+; Calculate x / 10 as (x * 2**32/10) / 2**32.
+; That is, we calculate the most significant word of the double-length
+; product. In fact, we calculate an approximation which may be 1 off
+; because we've ignored a carry from the least significant word we didn't
+; calculate. We correct for this by insisting that the remainder < 10
+; and by incrementing the quotient if it isn't.
+
+__16__rt_udiv10 ; udiv10 ;
+ MOV a2, a1
+ LSR a1, #1
+ LSR a3, a1, #1
+ ADD a1, a3
+ LSR a3, a1, #4
+ ADD a1, a3
+ LSR a3, a1, #8
+ ADD a1, a3
+ LSR a3, a1, #16
+ ADD a1, a3
+ LSR a1, #3
+ ASL a3, a1, #2
+ ADD a3, a1
+ ASL a3, #1
+ SUB a2, a3
+ CMP a2, #10
+ BLT %FT0
+ ADD a1, #1
+ SUB a2, #10
+0
+ RET
+
+;
+; Fast signed divide by 10: dividend in a1, divisor in a2.
+; Returns quotient in a1, remainder in a2.
+; Also destroys a3 and a4.
+; Quotient is truncated (rounded towards zero).
+; Make use of __rt_udiv10
+
+__16__rt_sdiv10
+ ASR a4, a1, #31
+ EOR a1, a4
+ SUB a1, a4
+
+ MOV a2, a1
+ LSR a1, #1
+ LSR a3, a1, #1
+ ADD a1, a3
+ LSR a3, a1, #4
+ ADD a1, a3
+ LSR a3, a1, #8
+ ADD a1, a3
+ LSR a3, a1, #16
+ ADD a1, a3
+ LSR a1, #3
+ ASL a3, a1, #2
+ ADD a3, a1
+ ASL a3, #1
+ SUB a2, a3
+ CMP a2, #10
+ BLT %FT0
+ ADD a1, #1
+ SUB a2, #10
+0
+ EOR a1, a4
+ SUB a1, a4
+ EOR a2, a4
+ SUB a2, a4
+ RET
+
+;
+; Test for division by zero (used when division is voided).
+
+__16__rt_divtest ; divtest ;
+ CMPS a1, #0
+ BEQ dividebyzero
+ RET
+
+dividebyzero
+ SUB sp, sp, #8*4 ; Room for R8..R15
+ PUSH {r0-r7}
+ MOV r7, lr
+ ADR r0, DivideByZeroError
+ BL save_regs_and_trap
+
+ ALIGN
+DivideByZeroError
+ DCD 1
+ DCB "divide by 0", 0
+ ALIGN
+
+ END