home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / documentation / documents / a252swi < prev    next >
Internet Message Format  |  1999-04-27  |  9KB

  1. From: enevill@acorn.co.uk (Edward Nevill)
  2. Subject: New SWI veneers
  3. Date: 4 Oct 91 17:11:01 GMT
  4. Organization: Acorn Computers Ltd, Cambridge, England
  5.  
  6. Here is an optimised SWI veneer which can be used instead of _kernel_swi.
  7. It is significantly faster than _kernel_swi and is much easier to use (IMHO).
  8.  
  9. Enjoy,
  10. Edward.
  11. --- swiv.h ---
  12. /* SWI veneers:
  13.  *  Written by Edward Nevill and Jonathan Roach in an idle moment between projects.
  14.  */
  15.  
  16. /* Anonymous Error type */
  17. typedef struct Error Error;
  18.  
  19. /* Generic SWI interface
  20.  *  swi(swino,mask,regs...)
  21.  *   swino = SWI number to call as defined in h.swis, X bit set if you wish the
  22.  *           X form of the SWI to be called, clear if you want the non X form.
  23.  *   reg_mask = mask of in / out registers
  24.  *              bits 0-9:   Bit N set => Register N specified on input
  25.  *                          Bit N clear => Register N unspecified on input
  26.  *              bits 22-31: Bit N set => Register N-22 on output stored
  27.  *                              in address specified in varargs list.
  28.  *   ...        In order, input registers followed by output registers,
  29.  *                      starting at r0 and going up.
  30.  *   returns 0 or errorblock pointer if X-bit set
  31.  *   returns r0 if X-bit clear
  32.  *  swix(swino,mask,regs...)
  33.  *   This behaves identically to 'swi' except that it always calls the X form.
  34.  *
  35.  * Eg:
  36.  *   swi(OS_SWINumberToString, IN(R0|R1|R2), n, buf, 255);
  37.  *   e = swi(XOS_SWINumberFromString, IN(R1)|OUT(R0), str, &n);
  38.  *       - Error block pointer (or 0) is returned so must get returned R0
  39.  *       - via argument list.
  40.  *   e = swix(OS_SWINumberFromString, IN(R1)|OUT(R0), str, &n);
  41.  *       - As above but uses the swix function rather that setting the X bit
  42.  *         explicitly (saves one instruction on SWI call).
  43.  *   e = swi(OS_File, IN(R0|R1|R2|R3)|OUT(R4), 255, name, buff, 0, &len);
  44.  *       - We don't care about the load, exec or attrs so don't specify
  45.  *         them in the output registers.
  46.  */
  47.  
  48. extern Error *swix(int swino, int reg_mask, ...);
  49. extern int swi(int swino, int reg_mask, ...);
  50.  
  51. /* Register mask macros
  52.  *  The bits in the register mask are arranged as follows:
  53.  *  31 30 29 ... 22 ...  8 ...  2  1  0
  54.  *  O0 O1 O2 ... O9     I9 ... I2 I1 I0  I(N) = bit set if R(N) used on entry
  55.  *                                       O(N) = bit set if R(N) written on exit
  56.  *  The bits are arranged like this to optimise the case where a SWI is being
  57.  *  called with a small number of input and output registers. For example, a SWI
  58.  *  call which uses R0-R5 on entry and R0-R1 on exit will have a register mask
  59.  *  of 0xC000003f which can be loaded into an ARM register in one instruction
  60.  *  (the compiler performs this optimisation, even when the constant wraps
  61.  *  around between bits 0 and 31). Using the more obvious coding of I0-I9 in bits
  62.  *  0 - 9 and O0-O9 in bits 16-23 leads to a constant of 0x0003003f which require
  63.  *  two instructions.
  64.  */
  65. #define IN(m) (m)
  66. #define OUT(m) ((unsigned)(m&1)<<31|(m&2)<<29|(m&4)<<27|(m&8)<<25|(m&16)<<23|\
  67.                 (m&32)<<21|(m&64)<<19|(m&128)<<17|(m&256)<<15|(m&512)<<13)
  68.  
  69. /* The register names
  70.  *  Change these to use different names if you use R0 - R9 elsewhere in your program
  71.  */
  72. #define R0 0x001
  73. #define R1 0x002
  74. #define R2 0x004
  75. #define R3 0x008
  76. #define R4 0x010
  77. #define R5 0x020
  78. #define R6 0x040
  79. #define R7 0x080
  80. #define R8 0x100
  81. #define R9 0x200
  82. --- swiv.s ---
  83. r0              RN      0
  84. r1              RN      1
  85. r2              RN      2
  86. r3              RN      3
  87. r4              RN      4
  88. r5              RN      5
  89. r6              RN      6
  90. r7              RN      7
  91. r8              RN      8
  92. r9              RN      9
  93. r10             RN      10
  94. r11             RN      11
  95. r12             RN      12
  96. sp              RN      13
  97. lr              RN      14
  98. pc              RN      15
  99.  
  100.  
  101.                 AREA    |C$$code|, CODE, READONLY
  102.  
  103. SWIReturnInst   LDR     pc, [sp, #0*4]
  104.  
  105.         EXPORT  swix
  106. swix    ROUT
  107.         ORR     r0, r0, #&20000
  108.  
  109.         EXPORT  swi
  110. swi     ROUT
  111.  
  112. ; Construct a stack frame that looks something like this:
  113. ;       returnval
  114. ;       LDMIA   r12!, {r0..rn}
  115. ;       SWI     xxxxxx
  116. ;       LDR     pc, [sp]
  117. ;       saved r4-r11,lr
  118. ;       saved r1
  119. ;       saved input values (r2...rn)
  120.  
  121.         STMFD   sp!, {r1-r3}            ; Save r1 and put 1st two variadic args on stack
  122.         BIC     r2, r0, #&ff000000
  123.         ORR     r2, r2, #&ef000000      ; Construct SWI instruction
  124.         ADR     r0, SWIReturn
  125.         BIC     r1, r1, #&ff000000      ; Construct LDMIA R12!, {regs} instruction, if
  126.         BICS    r1, r1, #&00ff0000      ; {regs} = {} (IE no input regs) we must not
  127.         ORRNE   r1, r1, #&e8000000      ; use an LDMIA R12!, {} instruction as this is an
  128.         ORRNE   r1, r1, #&00bc0000      ; invalid instruction, we use a suitable NOP instead
  129.         MOVEQ   r1, #0                  ; 0 = opcode for ANDEQ r0, r0, r0 (a suitable NOP)
  130.         LDR     r3, SWIReturnInst
  131.         STMFD   sp!, {r0-r9,r11,lr}     ; Save regs and set up SWI call routine (in R0-R3)
  132.         ADD     r12, sp, #(12+1)*4      ; Point R12 at input regs on stack.
  133.         ADD     pc, sp, #4              ; Call routine on stack
  134. SWIReturn
  135.         LDR     lr, [sp, #(12+0)*4]     ; Fetch reg mask again
  136.         MOVS    lr, lr, ASL #1          ; Shift out setting C if R0 to be written, N
  137.         LDRCS   r11, [r12], #4          ; if R1 to be written.
  138.         STRCS   r0, [r11]
  139.         LDRMI   r11, [r12], #4
  140.         STRMI   r1, [r11]
  141.         MOVS    lr, lr, ASL #2          ; Shift 2 bits each time for the next 2 regs
  142.         LDRCS   r11, [r12], #4
  143.         STRCS   r2, [r11]
  144.         LDRMI   r11, [r12], #4
  145.         STRMI   r3, [r11]
  146.         MOVS    lr, lr, ASL #2
  147.         LDRCS   r11, [r12], #4
  148.         STRCS   r4, [r11]
  149.         LDRMI   r11, [r12], #4
  150.         STRMI   r5, [r11]
  151.         MOVS    lr, lr, ASL #2
  152.         LDRCS   r11, [r12], #4
  153.         STRCS   r6, [r11]
  154.         LDRMI   r11, [r12], #4
  155.         STRMI   r7, [r11]
  156.         MOVS    lr, lr, ASL #2
  157.         LDRCS   r11, [r12], #4
  158.         STRCS   r8, [r11]
  159.         LDRMI   r11, [r12], #4
  160.         STRMI   r9, [r11]
  161.         LDR     r1, [sp, #2*4]
  162.         TST     r1, #&20000             ; X-bit clear
  163.         CMPEQ   pc, #&80000000          ; SET V flag if so, so R0 not cleared
  164.         MOVVC   r0, #0                  ; Clear R0 if no error (or X-bit clear)
  165.         ADD     sp, sp, #4*4            ; Drop SWI call routine
  166.         LDMIA   sp!, {r4-r9,r11,lr}
  167.         ADD     sp, sp, #3*4            ; Drop saved R1 and 1st two variadic args.
  168.         MOVS    pc, lr
  169.  
  170.         END
  171. --- switime.c ---
  172. /* This program times the 'swi' and '_kernel_swi' veneers. It calls the X form of
  173.  * OS_GenerateError (the fastest possible swi since all it does is set the V flag).
  174.  * It calls it with a sample register set which would be used to call XOS_ReadVarVal.
  175.  *
  176.  * IE. It sets up the registers as though it were calling XOS_ReadVarVal and then
  177.  * calls a trivial SWI (XOS_GenerateError) so that it only measure the overhead of
  178.  * calling a typical SWI.
  179.  *
  180.  * Timings for an A540 in mode 0
  181.  *                  swi      _kernel_sw
  182.  *  Cache enabled   168 csec 252 csec
  183.  *  Cache disabled  340 csec 497 csec
  184.  *
  185.  * It also serves as an example of how much easier the 'swi' veneer is to use. Note the
  186.  * 6 or 7 lines required using '_kernel_swi' compared with the one line using 'swi'.
  187.  */
  188. #include <stdio.h>
  189.  
  190. #include "kernel.h"
  191. #include "swiv.h"
  192. #include "swis.h"
  193.  
  194. int main(void)
  195. {
  196.     _kernel_swi_regs r;
  197.     int t1, t2, t3;
  198.     int i;
  199.     int exists;
  200.  
  201.     t1 = swi(OS_ReadMonotonicTime, 0);
  202.     for (i = 0; i < 100000; i++)
  203.         swix(OS_GenerateError, IN(R0|R2|R3|R4)|OUT(R2), "ADFSFiler$Path", -1, 0, 0, &exists);
  204.     t2 = swi(OS_ReadMonotonicTime, 0);
  205.     for (i = 0; i < 100000; i++) {
  206.         r.r[0] = (int)"ADFSFiler$Path";
  207.         r.r[2] = -1;
  208.         r.r[3] = 0;
  209.         r.r[4] = 0;
  210.         _kernel_swi(OS_GenerateError, &r, &r);
  211.         exists = r.r[2];
  212.     }
  213.     t3 = swi(OS_ReadMonotonicTime, 0);
  214.     printf("Times:-\nswix = %d csec\n_kernel_swi = %d csec\n", t2-t1, t3-t2);
  215.     return 0;
  216. }
  217. ---
  218.  
  219.  
  220. From: enevill@acorn.co.uk (Edward Nevill)
  221. Subject: New SWI veneers (2)
  222. Date: 21 Oct 91 16:01:22 GMT
  223. Organization: Acorn Computers Ltd, Cambridge, England
  224.  
  225. A couple of weeks ago I posted a set of variadic swi wrapper
  226. routines, unfortunately they contained a bug.
  227.  
  228. The macro OUT defined in h.swiv currently reads
  229.  
  230. #define OUT(m) ((unsigned)(m&1)<<31|(m&2)<<29|(m&4)<<27|\
  231.                 (m&8)<<25|(m&16)<<23|(m&32)<<21|(m&64)<<19|\
  232.                 (m&128)<<17|(m&256)<<15|(m&512)<<13)
  233.  
  234. it should read
  235.  
  236. #define OUT(m) ((unsigned)((m)&1)<<31|((m)&2)<<29|((m)&4)<<27|\
  237.                 ((m)&8)<<25|((m)&16)<<23|((m)&32)<<21|((m)&64)<<19|\
  238.                 ((m)&128)<<17|((m)&256)<<15|((m)&512)<<13)
  239.  
  240. IE. it should have a pair of brackets around each 'm' in the
  241. macro expansion.
  242.  
  243. Given that a typical use of the macro is something like OUT(R0|R1)
  244. this can lead to fatal results (eg address exceptions, stack
  245. trampling) so you should change your headers to use the new macros.
  246.  
  247. Edward.
  248.  
  249.  
  250.