; ; oxswi.s ; ; Original version of _swi[x] SWI veneers ; ; © 1994 Straylight ; ;----- Licensing note ------------------------------------------------------- ; ; This file is part of Straylight's C library stubs (xstubs). ; ; xstubs is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2, or (at your option) ; any later version. ; ; xstubs is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with xstubs. If not, write to the Free Software Foundation, ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ;----- Standard header ------------------------------------------------------ GET libs:header GET libs:swis GET libs:stream ;----- Main code ------------------------------------------------------------ AREA |C$$code|,CODE,READONLY ; --- _swi, _swix --- ; ; On entry: R0 == SWI number ; R1 == flags ; R2,R3 == arguments ; More arguments on stack ; ; On exit: R0 == output register, if any ; ; Use: Generalised SWI veneer, compatible with Acorn's latest. EXPORT |_swi| EXPORT |_swix| swi ROUT |_swi| MOV R12,R13 ;Keep stack pointer safe STMFD R13!,{R2,R3} ;Save variadic args on stack STMFD R13!,{R4-R12,R14} ;Save loads of other regs ADR R10,%20swi ;Go to the SWI return pt B %00swi ;Do the main job thing |_swix| MOV R12,R13 ;Keep stack pointer safe STMFD R13!,{R2,R3} ;Save variadic args on stack STMFD R13!,{R4-R12,R14} ;Save loads of other regs ORR R0,R0,#&20000 ;Set the SWI's X bit BIC R1,R1,#&000F0000 ;Make it return R0 ADR R10,%10swi ;Go to the SWIX return pt ; --- Build entry stack frame --- 00swi MOV R2,R1,LSL #22 ;Get the input registers MOVS R2,R2,LSR #22 ORRNE R2,R2,#&E8000000 ;Build that as an LDMIA ORRNE R2,R2,#&00BC0000 ;Based on R12 (ip) ANDS R3,R1,#&800 ;Does he want a local block? BLNE %80swi ;Yes -- better find it then ORR R4,R0,#&EF000000 ;Build the SWI instruction MOV R6,#&E1000000 ;Build a MOV skeleton ORR R6,R6,#&00A00000 AND R5,R1,#&000F0000 ;Get return register value ORR R5,R6,R5,LSR #16 ;Put in the source register ORR R5,R5,#&0000E000 ;Put in destination ORR R6,R6,#&0000F000 ;Set up return instruction ORR R6,R6,#&0000000A SUB R12,R12,#8 ;Find variadic arguments STMFD R13!,{R2-R6} ;Build SWI-calling frame BARRIER MOV R11,R1 ;Look after the flags word MOV PC,R13 ;And call the stack code ; --- Process a return from the SWI --- 10swi MOVVC R14,#0 ;If no error, return 0 20swi STR PC,[R13,#0] ;Save my program counter ; --- Output the output registers --- MOVS R11,R11,LSL #1 ;Shift bits to C and N LDRCS R10,[R12],#4 ;If we write R0, find addr STRCS R0,[R10,#0] ;And write it out LDRMI R10,[R12],#4 ;If we write R1, find addr STRMI R1,[R10,#0] ;And write it out MOVS R11,R11,LSL #2 ;Move next two bits out LDRCS R10,[R12],#4 ;If we write R2, find addr STRCS R2,[R10,#0] ;And write it out LDRMI R10,[R12],#4 ;If we write R3, find addr STRMI R3,[R10,#0] ;And write it out TST R11,#&7F000000 ;Any more to do? BEQ %30swi ;No -- save 16 cycles MOVS R11,R11,LSL #2 ;Move next two bits out LDRCS R10,[R12],#4 ;If we write R4, find addr STRCS R4,[R10,#0] ;And write it out LDRMI R10,[R12],#4 ;If we write R5, find addr STRMI R5,[R10,#0] ;And write it out MOVS R11,R11,LSL #2 ;Move next two bits out LDRCS R10,[R12],#4 ;If we write R6, find addr STRCS R6,[R10,#0] ;And write it out LDRMI R10,[R12],#4 ;If we write R7, find addr STRMI R7,[R10,#0] ;And write it out MOVS R11,R11,LSL #2 ;Move next two bits out LDRCS R10,[R12],#4 ;If we write R8, find addr STRCS R8,[R10,#0] ;And write it out LDRMI R10,[R12],#4 ;If we write R9, find addr STRMI R9,[R10,#0] ;And write it out TST R11,#&40000000 ;Is the `write PC' bit set? LDRNE R0,[R13,#0] ;Yes -- load the one I saved LDRNE R10,[R12],#4 ;Load the address STRNE R0,[R10,#0] ;And write the PC value out 30swi ADD R13,R13,#20 ;Restore the stack pointer MOV R0,R14 ;Get the return value LDMFD R13!,{R4-R11,R13,PC}^ ;And return to caller ; --- Work out address of literal block --- 80swi MOVS R4,R1,LSL #1 ;Look after flags word MOV R5,#6 ;Simple counter thingy AND R3,R1,#&0000F000 ;Get the block register ORR R3,R3,#&E2000000 ;Build into ADD instruction ORR R3,R3,#&008C0000 85swi ADDCS R3,R3,#4 ;Move pointer on for each reg ADDMI R3,R3,#4 SUBS R5,R5,#1 ;Decrement counter too MOVLE PC,R14 ;If finished, return MOVS R4,R4,LSL #2 ;Shift next two bits out B %85swi ;And loop round again LTORG ;----- That's all, folks ---------------------------------------------------- END