home *** CD-ROM | disk | FTP | other *** search
- Y E T A N O T H E R S W I V E N E E R
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- Introduction
- ~~~~~~~~~~~~
-
- This document is about another way of accessing SWIs from C. It explains,
- in no particular order:
-
- * Why I've rewritten it
- * How to use it
- * What's nicer about my one
-
-
- The story behind it
- ~~~~~~~~~~~~~~~~~~~
-
- A while ago, Acorn wrote a couple of functions to call SWIs from C. They
- were called _swi and _swix (_swix will return errors, _swi won't). These
- routines actually have quite a nice programmer interface, which feels vaguely
- natural from C. A copy of these routines is contained within the
- SharedCLibrary module in RISC OS 3. The new CLib stubs will allow you to
- access these routines, at the cost of losing compatibility with RISC OS 2.
- There's nothing you can do about this; if you use the new stubs, you can't
- use the RISC OS 2 CLib. And just to help, the new C compiler generates
- different names for the run-time support functions it needs (e.g. it tries to
- call __rt_stkovf_split_small instead of x$stack_overflow) and the old stubs
- don't declare these names. (The routines are identical, it's just that
- they're called different names now.)
-
- As many people will no doubt know, I've been working on a dynamic linking
- system for ages (the code is done -- I'm trying to get the documentation into
- a readable state still). Part of this system is some replacement
- SharedCLibrary stubs, which interface neatly with the rest of the system so
- that things are handled automatically on startup.
-
- My stubs are intended to be drop-in replacements for the Acorn ones.
- Actually, they're quite a bit smaller (almost as small as GSTStubs,
- apparently), so I tend to use them all the time. The new versions contain
- the old and new names for the run-time support functions. However, I was
- put into a bit of a dilemma by the new entry points, since if I include
- interfaces to the new routines, the stubs won't work under RISC OS 2, whereas
- if I don't include them, they won't be compatible with the Acorn ones any
- more. My solution was to have two versions, one which included the new entry
- points and one which doesn't. And so you *can* have your cake and eat it, I
- decided to write my own version of these new routines so I could give it
- away, for people who want to use them under RISC OS 2.
-
- While I was testing my implementation, I came across a bug in the Acorn
- version. My one doesn't have this bug (described below) -- another good
- reason for me to have replaced it.
-
-
- How to use the veneers
- ~~~~~~~~~~~~~~~~~~~~~~
-
- The two functions are very similar to each other:
-
- int _swi(int swi_no,int flags,...);
- _kernel_error *_swix(int swi_no,int flags,...);
-
- The arguments are the same in both cases.
-
- The interesting bit of these routines is the flags word. A collection of
- macros is supplied (they've been augmented a bit by me and others since the
- original Acorn versions), to allow you to specify what to do with all the
- registers. You just add together the values you want.
-
- _in(n) Specify Rn as being an input register
- _inr(m,n) Specify Rm-Rn as being input registers
- _out(n) Specify Rn as being an output register
- _outr(m,n) Specify Rm-Rn as being output registers
- _return(n) Return the value of Rn as the value of the function
- _block(n) Point Rn at `local block' on entry to the SWI
-
- _inr and _outr are nonstandard. Also, the standard versions are upper case.
- My version allows both, and I prefer the lower, because I find that the call
- gets less cluttered. The macros work on both versions of the routines -- you
- just use your favourite one.
-
- _return is only allowed in calls to _swi -- the return value of _swix is
- always the error pointer (0 for no error, otherwise it's a pointer to the
- number and string of the error, as usual).
-
- As well as register numbers, you can also specify the special value _flags to
- indicate that _swi or _swix should either output or return the processor
- flags.
-
- If you don't want any flags at all, pass 0 as the flags value.
-
- Both routines take an arbitrary number of arguments, from 2 upwards (if you
- give too many, the excess ones are just ignored). The arguments you pass are
- as follows, in order:
-
- One word (int or pointer, usually) for each input (_in) register, in
- ascending numerical order
-
- One address of a word (again, an int or pointer usually) for each
- output (_out) register, again in ascending numerical order
-
- The address of a word in which to store the flags, if applicable
-
- Any values to build into the local block
-
- The `local block' is just built from the excess arguments you pass. You can
- set up a register to point to the block if you want; that way you can easily
- build a parameter block in the function call and let the compiler get on with
- the tedious business of storing all the values individually.
-
- Some examples will probably help clear up any confusion:
-
- int currentTime=_swi(OS_ReadMonotonicTime,_return(0));
- /* Read current value of timer */
-
- int taskh=_swi(Wimp_Initialise,_inr(0,2)+_return(1),
- 200,0x4b534154,"MyTaskName");
- /* Initialise a WIMP task */
-
- _swi(Wimp_SetIconState,_block(1),wind,icn,0,0);
- /* Prod an icon into redrawing */
-
- _swi(OS_ReadC,0); /* Wait for a keypress */
-
- int x,y,b;
- _swi(OS_Mouse,_outr(0,2),&x,&y,&b);
- /* Read current mouse position */
-
- if (_swi(OS_ReadEscapeState,_return(_flags)) & _c)
- /* Do something */ /* Check the escape state */
-
- As I hope you can see, it's actually rather a powerful design. Full credit
- for this goes to Acorn on this one. I just rewrote the code. They'd already
- done the hard bit.
-
- The _inr and _outr macros, put to good use above, are not mine either, and
- credit for them, and their implementations, goes to Brian Brunswick.
-
- Blame for the contrived examples above is justifiably aimed at me, though,
- as are any bugs I've missed in the code.
-
-
- Differences between the implementations
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- The idea was to make the Straylight version identical to the Acorn one. This
- is almost what has happened, although there are some differences you should
- be aware of:
-
- 1. The Acorn implementation contains a bug which makes it set the address
- of a local block argument incorrectly if R0 is one of the _out()
- registers. The Straylight version does not have this bug (or any others
- that I know about).
-
- 2. The Straylight implementation is 40 bytes smaller than the Acorn one.
- However, to be fair, the Acorn version is actually embedded in the
- SharedCLibrary under RISC OS 3, so you gain big here. On the other
- hand, it would be trivial for me to make the Straylight version
- dynamically linkable to get the same advantage. (It would be fairly
- pointless too, really, but I could do it, just the same.)
-
- 3. The Acorn implementation is slightly slower. This is largely by
- accident, actually. For those interested, a breakdown of the timings is
- given below. For those who aren't, the differences are worth worrying
- about in practice.
-
- 4. The Straylight implementation of _swix will store register values even
- if the SWI returned an error. The Acorn version won't do this. This
- is intentional -- occasionally useful information is returned here. If
- anyone doesn't like this, let me know and I may change it.
-
- 5. Source code to the Acorn version is available (see the Memphis
- distribution, in FSLib.s.swiv). Straylight don't release source, so
- you'll have to give up there.
-
-
- Timing comparison
- ~~~~~~~~~~~~~~~~~
-
- The timings are presented in terms of ARM2 S-cycles (so I've counted an N as
- 2S and so on). It makes things simpler this way. Neither tries to do
- anything really clever with N cycles, so it doesn't make a lot of difference.
-
- Note that trying to read _out() values of registers greater than a certain
- threshhold (R3 for the Straylight version, R4 for the Acorn one) will cause
- the routine to take longer. Trying to return the flags will pass this
- threshhold in both versions. Note too that _swix is ever so slightly quicker
- than _swi in both cases.
-
- Straylight Acorn
-
- Base time 102 108
-
- _swi rather than _swix +1 +4
- Local block argument +60 +56
- For each input register +1 +1
- No input registers +1 +1
- For each output register +6 +6
- For outputting the flags +9 +9
- For passing output threshhold +16 +13
-
- Best case time 103 109
- Worst case time 259 261
-
- I don't consider the speed difference to be terribly significant; I'm
- actually much more worried about the 40 bytes size difference here, since
- SWIs usually take a fairly long time anyway.
-
-
- I hope someone somewhere finds this useful. Otherwise I've wasted a lot of
- time typing all this in.
-
-
- Mark Wooding
- Straylight
- --
- (' t r a y l i g h t / `Clearly now the past mistakes
- ,_) csuov@csv.warwick.ac.uk / The giant steps we had to take
- / The path that ever promise made
- Mark Wooding / To die in dream, dissolve and fade'
-