/*
 * 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,<struct> *obj,<struct> *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,<struct> *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
 * %[<type>]<n>, where <type> is: `s' string, `x' hex number, `i' decimal
 * integer, `c' single character, and <n> 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 a<b,
 * a==b or a>b.
 */

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
 * <name>[`:'<default>] -- 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
