/* * sapphire.h * * Definitions for using Sapphire from C * * © 1995 Straylight */ #if !defined(__CC_NORCROFT) || !defined(__arm) #error You must use the Norcroft ARM Compiler for Sapphire programs #endif #pragma force_top_level #pragma include_only_once #ifndef __sapphire_h #define __sapphire_h /*----- Note --------------------------------------------------------------* * * This header file contains definitions and directives which are highly * compiler specific. Only use /genuine/ Norcroft ARM C compilers! */ /*----- Important types ---------------------------------------------------*/ /* --- error --- * * * Defines the layout of a RISC OS error /again/. If you're using * _kernel_oserror, then #define error _kernel_oserror some time, and * everything should be OK. */ #ifndef error typedef struct { int errnum; char errmess[252]; } error; #endif /* --- regset --- * * * Defines a register block, which is the only sane way of fiddling with * registers from C. */ typedef struct { int r[13]; unsigned int flags; } regset; /* --- Hacky definition of a routine --- * * * This prevents attempts to call Sapphire routines directly, while still * making references to routines look sensible, and preventing fiddling * with the code, which would (of course) be a Bad Thing. */ typedef struct _opaque routine[]; /* --- size_t --- * * * In case no-one else has defined it yet. */ #ifndef __size_t #define __size_t typedef unsigned size_t; #endif /*----- Sapphire-to-C veneers ---------------------------------------------*/ /* --- __sapph_veneer --- * * * This routine is used internally by the _sapph macro to build * callable-from-Sapphire functions in C. */ extern void __sapph_veneer(void); /* --- _sapph --- * * * Allows you to build callable-from-Sapphire functions in C. The syntax * is * * _sapph(foo)(regset *r, *obj, *wsp,char *scratch) * { * // ... * } * * The routine must return an int built by using the macros below, for * setting flags on exit. * * The obj and wsp pointers are the values of R10 and R12 respectively on * entry. Conventionally, these are `object' pointers (like a `this' pointer * in C++) and `workspace' pointers (not really used in C), but can actually * be anything you like. If you're not interested in the values, you * are allowed to omit them. For example, * * _sapph(foo)(regset *r, *obj) * * is also permissable, because of the way that APCS works. If you're * feeling adventurous, you can use extra arguments to pull off values * of R0 onwards off the stack. This starts getting a bit hacky, though. * Alternatively, you can use variadic arguments and fiddle with stdarg * to access these. This isn't really recommended. * * For reference, the code built by the macro is as follows: * * STMFD R13!,{R14} * MOV R14,PC * B csapph_veneer */ #define _sapph(name) \ void name(void){_word(0xE92D4000);_word(0xE1A0E00F);__sapph_veneer();} \ int __sapph__##name /* --- Macros for returning flags --- * * * You can OR these together using the | operator to obtain interesting * effects. For example, * * return (V_set | C_clear); * * would return V set, and C clear, but the other two flags would be * preserved. The default (0) is to preserve all the flags. * * If you really want to be strange, nibble 1 is used to BIC the flags, * and nibble 0 is EORed with them. Alternatively, you can fiddle with * the `flags' member of the regset structure. */ #define V_set 0x11 #define V_clear 0x10 #define C_set 0x22 #define C_clear 0x20 #define Z_set 0x44 #define Z_clear 0x40 #define N_set 0x88 #define N_clear 0x80 /* --- C-to-Sapphire veneers --- */ /* --- call --- * * * Arguments: routine p == the routine to call * regset *r == pointer to register block to use * * Returns: Zero, if no error was returned, or a pointer to the error. * * Use: Calls a general Sapphire routine. The routine is entered * with registers as defined in the regset block. Flags are * returned in the `flags' member of the regset. The flags * are all cleared on entry to the routine. */ extern error *call(routine /* p */, regset */* r */); /* --- _call, _callx --- * * * Arguments: routine p == the routine to call * unsigned flags == various flags controlling arguments * ... == a list of arguments and things * * Returns: For _call, the _return register (0 by default). For _callx, * zero if no error, or a pointer to the error. * * Use: Calls a Sapphire routine. Only R0-R9 can be passed. The * flags are described below. The optional arguments are in * the following order: * * Input registers: One word for each input register * Output registers: Address to store each reg value * Flags address: Address to store PC+flags value * Block contents: Build contents of local block at end */ extern int _call(routine /* p */, unsigned /* flags */, ...); extern error *_callx(routine /* p */, unsigned /* flags */, ...); /*----- SWI veneers -------------------------------------------------------*/ /* --- swi --- * * * Arguments: int swi == SWI number to call * regset *r == registers to pass * * Returns: Pointer to error, or 0 * * Use: Calls a SWI. Returned registers are stored in the regset, * as are the flags. */ extern error *swi(int /* swi */, regset */* r */); /* --- _swi, _swix --- * * * Arguments: int swi == number of the SWI to call * unsigned flags == various flags controlling arguments * ... == a list of arguments and things * * Returns: For _swi, the _return register (0 by default). For _swix, * zero if no error, or a pointer to the error. * * Use: Calls a SWI. The flags are described below. The optional * arguments are as above. */ extern int _swi(int /* swi */, unsigned /* flags */, ...); extern error *_swix(int /* swi */, unsigned /* flags */, ...); /*----- Flags for the veneers ---------------------------------------------*/ /* --- _flags -- return or output processor flags --- */ #define _flags (0x10) /* --- _in and _inr -- input a register, or a range of registers --- */ #define _in(r) (1u << (r)) #define _inr(ra,rb) (((~0) << (ra)) ^ ((~0) << ((rb)+1))) /* --- _out and _outr -- output a register, or a range of registers --- */ #define _out(r) (1u << (31-((r) == _flags ? 10 : (r)))) #define _outr(ra,rb) (((~0) << (31-(rb))) ^ ((~0) << (32-(ra)))) /* --- _block -- point a register at block built from arguments --- */ #define _block(r) (((r) << 12) | 0x800) /* --- _return -- return register from _swi (not _swix) --- */ #define _return(r) ((r) == _flags ? 0xF0000 : (r) << 16) /* --- Constants for ARM processor flags --- */ #define _n (0x80000000u) #define _z (0x40000000u) #define _c (0x20000000u) #define _v (0x10000000u) /* --- Acorn style capital-letter macros --- */ #define _FLAGS _flags #define _IN(x) _in(x) #define _INR(x,y) _inr(x,y) #define _OUT(x) _out(x) #define _OUTR(x,y) _outr(x,y) #define _BLOCK(x) _block(x) #define _RETURN(x) _return(x) #define _N _n #define _Z _z #define _C _c #define _V _v /*----- C library support -------------------------------------------------* * * We have to mess about with some bits of the header files, mainly to * point the compiler at bits of Sapphire instead of the normal library. * To support a dynamically linked environment, we need to access static * data items through `finder' functions, declared __pure to allow the * compiler to optimise slightly better. */ /* --- errno --- */ #ifdef errno #undef errno #endif extern __pure int *cmath_errno(void); #define errno (*cmath_errno()) /* --- math --- * * * Sapphire's normal `sqrt' routine is an integer square root (courtesy of * David Seal), so we need to cheat a bit here. */ #ifdef HUGE_VAL #undef HUGE_VAL #endif extern __pure double cmath_huge(void); #define HUGE_VAL (cmath_huge()) #define sqrt(x) __sapph_sqrt(x) /* --- ctype --- * * * We define macros for toupper and tolower, since this is very simple under * the Sapphire implementation of ctype. */ #ifdef __ctype #undef __ctype #endif extern __pure char *ctype_findTable(void); #define __ctype (ctype_findTable()) #define tolower(c) (isupper(c) ? __ctype[c+256] : c) #define toupper(c) (islower(c) ? __ctype[c+256] : c) /* --- Memory moving routines --- */ extern void fastMove(void * /* a */, void */* b */, size_t /* s */); #define memmove(a, b, s) fastMove(a, b, s) #define memcpy(a, b, s) fastMove(a, b, s) /*----- Basic Sapphire routines -------------------------------------------*/ /* --- Access to Sapphire environment block --- */ extern __pure char *__sapph_scratchpad(void); #define scratchpad (__sapph_scratchpad()) #define scratch(t) ((t)__scratchpad()) /* `scratchpad' is the address of a buffer of at least 256 bytes, which * you can use more or less as you want to. */ /* --- Simple string functions --- * * * These functions are veneers onto the standard Sapphire routines. Hence * their behaviour deviates slightly from the ANSI definitions. The Sapphire * implementations have been written mainly for simplicity and size, rather * than speed. If string handling becomes time critical, it's probably a * good idea to use better lookup structures. */ #define strcpy(d, s) str_cpy(d, s) extern char *strcpy(char */* d */, const char */* s */); /* Copies a string from source to destination. Note: Returns pointer to * terminating null byte, /not/ input value of d as required by ANSI. We * think it's more useful like this, and the ANSI result isn't used often * enough for compatiblity to be an issue. */ #define strlen(s) str_len(s) extern int strlen(const char */* s */); /* Returns the length of a string. */ extern char *strsubst(const char */* skel */, char */* buff */, ...); /* Veneer to Sapphire's str_subst routine. In summary, it copies the * skeleton string to the buffer, replacing placeholders of the form * %[], where is: `s' string, `x' hex number, `i' decimal * integer, `c' single character, and is the argument number, from 0 * through 9. Returns a pointer to the beginning of the buffer. */ extern int strcmp(const char * /* a */, const char */* b */); /* Compares two strings, returning <0, ==0 or >0 according to whether ab. */ extern int stricmp(const char */* a */, const char */* b */); /* Compares to strings in a case-insensitive manner. Returns as strcmp. */ extern char *strbuffer(void); /* Returns the address of a 256-byte buffer. There are two buffers, which * are returned alternately. */ extern error *strerror(int /* num */, const char */* string */, ...); /* Builds an error in a buffer, as returned by strbuffer. The string * contains placeholders as for strsubst. */ /* --- Message routines --- */ #define msgs_lookup(tag) __sapph_msgs_lookup(tag) extern char *msgs_lookup(const char */* tag */); /* Translates the given message tag into a string. The tag has the form * [`:'] -- if the name couldn't be found, and a default was * specified, the default is returned. We prefer to use plain tags, and * put all messages in the messages file, unless it's possible that the * messages haven't been loaded yet. */ #define msgs_error __sapph_msgs_error extern error *msgs_error(int /* num */, const char */* tag */, ...); /* Builds an error message, like strerror, except that the string is * translated first. */ /* --- Memory allocation --- */ extern void *malloc(size_t /* size */); /* Allocate a block of memory from a heap. The block won't move around. */ #define free(p) __sapph_free(p) extern void free(void * /* p */); /* Free a block of memory allocated by malloc. */ #define alloc_error(x) __sapph_alloc_error(x) extern error *alloc_error(void); /* Return a pointer to an error about lack of memory. This is used to * build helpful error messages to send to the user. */ #define flex_alloc(a,s) __sapph_flex_alloc(a,s) extern void *flex_alloc(void */* a */, size_t /* s */); /* Allocate a block from the flex heap. Returns a pointer to the block, * or zero if no memory. */ #define flex_free(a) __sapph_flex_free(a) extern void flex_free(void */* a */); /* Frees a flex block. */ #define flex_size(a) __sapph_flex_size(a) extern size_t flex_size(void */* a */); /* Returns the size of a flex block. */ #define flex_extend(a,s) __sapph_flex_extend(a,s) extern void *flex_extend(void */* a */, size_t /* s */); /* Resize a block. s is the new size. Returns a pointer to the block, or * zero. */ #define flex_midExtend(a, w, b) __sapph_flex_midExtend(a, w, b) extern void *flex_midExtend(void */* a */, size_t /* w */, int /* b */); /* Inserts b bytes in the block at offset w. Returns a pointer to the block * or zero. */ #define flex_save(p) __sapph_flex_save(p) extern void flex_save(void */* p */); /* Saves a pointer p on the relocation stack. */ #define flex_load(x) __sapph_flex_load(x) extern void *flex_load(void); /* Restores a pointer from the relocation stack. */ /*----- Sapphire routines -------------------------------------------------*/ /* --- sapphire_init --- * * * On entry: R0 == pointer to application name * R1 == application's workspace size * R2 == size of stack required * * On exit: R10 == pointer to heap base * R11 == pointer to ScratchPad * R12 == pointer to application workspace * R13 == pointer to full descending stack * Other registers are corrupted * * Use: Initialises the Sapphire kernel, sets up the memory map, * and allocates workspace for library and client units. The * initialisation performed is fairly minimal; in particular, * the library units are not initialised -- you must call * sapphire_libInit for this to take place. This allows you * to check command line arguments etc. before initialising * the Wimp. */ extern routine sapphire_init; /* --- sapphire_disable --- * * * On entry: R0 == pointer to 0-terminated list of initialise routines * * On exit: -- * * Use: Prevents the given initialisation routines from being called. * This is mainly useful in the dynamic-linking environment, * where all Sapphire units are normally active. This routine * allows you to inactivate units which for example do not * have the resources they require, or use up unnecesary * memory. */ extern routine sapphire_disable; /* --- sapphire_libInit --- * * * On entry: -- * * On exit: -- * * Use: Initialises the Sapphire library and client units. */ extern routine sapphire_libInit; /* --- sapphire_doInit --- * * * On entry: R0 == pointer to application name * R1 == client workspace size * R2 == requested stack size * R3 == pointer to initialisation table * * On exit: R10 == base address of Sapphire heap * R11 == pointer to scratchpad and global data * R12 == pointer to client global workspace * R13 == pointer to a full descendion stack * * Use: Performs initialisation of the Sapphire library and the * client's sections. This is intended for use by the Sapphire * stub, while initialising the dynamically linked version of * Sapphire. */ extern routine sapphire_doInit; /* --- sapphire_doLibInit --- * * * On entry: R0 == address of library initialisation table * * On exit: -- * * Use: Initialises all currently uninitialised library units. */ extern routine sapphire_doLibInit; /* --- sapphire_doDisable --- * * * On entry: R0 == pointer to list of initialise routines to disable * R1 == pointer to initialisation table * * On exit: -- * * Use: Prevents the given initialisation routines from being * called. This is mainly useful in a dynamically linked * environment. */ extern routine sapphire_doDisable; /* --- sapphire_heapAddr --- * * * On entry: -- * * On exit: R1 == pointer to the heap base (for passing to OS_Heap) * * Use: Returns the address of the Sapphire heap. */ extern routine sapphire_heapAddr; /* --- sapphire_appName --- * * * On entry: -- * * On exit: R0 == pointer to application name (NULL terminated) * * Use: Returns a pointer to the application's name. */ extern routine sapphire_appName; /* --- sapphire_resetStack --- * * * On entry: -- * * On exit: R13 == stack pointer * * Use: Resets R13 to point to the top of the stack. */ extern routine sapphire_resetStack; /* --- sapphire_global --- * * * On entry: R0 == magic identifier for global variable * R1 == size of area required * * On exit: R0 == pointer to area * CS if the area already exists, CC otherwise * * Use: Locates (and creates if necessary) a `named' global area * which can be used for inter-section communication without * the necessity for dependencies. * * There is a limit on the number of global areas allowed, but * this can be raised fairly easily if necessary. * * If an area can't be created, an error is generated. */ extern routine sapphire_global; /* --- Data relative to R11 --- */ #define sapph__R11 0 #define sapph_scratchpad (sapph__R11-0) #define sapph_workspace (sapph__R11-4) #define sapph_stackBase (sapph__R11-8) #define sapph_heapBase (sapph__R11-12) #define sapph_appName (sapph__R11-16) #define sapph_clientWS (sapph__R11-20) /*----- That's all, folks -------------------------------------------------*/ #endif