source: rtems/cpukit/score/cpu/bfin/cpu_asm.S @ d9a6ab3

4.104.114.84.9
Last change on this file since d9a6ab3 was d9a6ab3, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 23, 2006 at 5:17:50 PM

2006-10-23 Joel Sherrill <joel@…>

  • .cvsignore, ChangeLog?, Makefile.am, cpu.c, cpu_asm.S, irq.c, preinstall.am, rtems/asm.h, rtems/score/bfin.h, rtems/score/cpu.h, rtems/score/cpu_asm.h, rtems/score/types.h: New files.
  • Property mode set to 100644
File size: 8.9 KB
Line 
1/*  cpu_asm.S
2 *
3 *  This file contains the basic algorithms for all assembly code used
4 *  in the Blackfin port of RTEMS.  These algorithms must be implemented
5 *  in assembly language
6 *
7 *  Copyright (c) 2006 by Atos Automacao Industrial Ltda.
8 *             written by Alain Schaefer <alain.schaefer@easc.ch>
9 *                    and Antonio Giovanini <antonio@atos.com.br>
10 *
11 *  The license and distribution terms for this file may be
12 *  found in the file LICENSE in this distribution or at
13 *  http://www.rtems.com/license/LICENSE.
14 *
15 *  $Id$
16 */
17 
18 
19#include <rtems/asm.h>
20#include <rtems/score/cpu_asm.h>
21#include <rtems/score/bfin.h>
22
23
24/*  _CPU_Context_switch
25 *
26 *  This routine performs a normal non-FP context switch.
27 *
28 *  bfin Specific Information:
29 *
30 *  For now we simply save all registers.
31 * 
32 */
33
34.globl __CPU_Context_switch
35__CPU_Context_switch:
36    /* Start saving context R0 = current, R1=heir */
37    /*save P0 first*/
38    [FP+0x8] = P0;
39    P0 = R0;
40    [ P0 + R0_OFFSET ] = R0;
41    [ P0 + R1_OFFSET] = R1;
42    [ P0 + R2_OFFSET] = R2;
43    [ P0 + R4_OFFSET] = R4;
44    [ P0 + R3_OFFSET] = R3;
45    [ P0 + R5_OFFSET] = R5;
46    [ P0 + R6_OFFSET] = R6;
47    [ P0 + R7_OFFSET] = R7;
48    [ P0 + P1_OFFSET] = P1;
49    /* save the original value of P0 */
50    P1 = [FP+0x8];
51    [ P0 + P0_OFFSET] = P1;
52    [ P0 + P2_OFFSET] = P2;
53    [ P0 + P3_OFFSET] = P3;
54    [ P0 + P4_OFFSET] = P4;
55    [ P0 + P5_OFFSET] = P5;
56    [ P0 + FP_OFFSET] = FP;
57    [ P0 + SP_OFFSET] = SP;
58   
59    /* save ASTAT */
60    R0 = ASTAT;
61    [P0 + ASTAT_OFFSET] = R0;
62
63    /* save Loop Counters */
64    R0 = LC0;
65    [P0 + LC0_OFFSET] = R0;
66    R0 = LC1;
67    [P0 + LC1_OFFSET] = R0;
68
69    /* save Accumulators */
70    R0 = A0.W;
71    [P0 + A0W_OFFSET] = R0;
72    R0 = A0.X;
73    [P0 + A0X_OFFSET] = R0;
74    R0 = A1.W;
75    [P0 + A1W_OFFSET] = R0;
76    R0 = A1.X;
77    [P0 + A1X_OFFSET] = R0;
78   
79    /* save Index Registers */
80    R0 = I0;
81    [P0 + I0_OFFSET] = R0;
82    R0 = I1;
83    [P0 + I1_OFFSET] = R0;
84    R0 = I2;
85    [P0 + I2_OFFSET] = R0;
86    R0 = I3;
87    [P0 + I3_OFFSET] = R0;
88
89    /* save Modifier Registers */
90    R0 = M0;
91    [P0 + M0_OFFSET] = R0;
92    R0 = M1;
93    [P0 + M1_OFFSET] = R0;
94    R0 = M2;
95    [P0 + M2_OFFSET] = R0;
96    R0 = M3;
97    [P0 + M3_OFFSET] = R0;
98
99    /* save Length Registers */
100    R0 = L0;
101    [P0 + L0_OFFSET] = R0;
102    R0 = L1;
103    [P0 + L1_OFFSET] = R0;
104    R0 = L2;
105    [P0 + L2_OFFSET] = R0;
106    R0 = L3;
107    [P0 + L3_OFFSET] = R0;
108
109    /* Base Registers */
110    R0 = B0;
111    [P0 + B0_OFFSET] = R0;
112    R0 = B1;
113    [P0 + B1_OFFSET] = R0;
114    R0 = B2;
115    [P0 + B2_OFFSET] = R0;
116    R0 = B3;
117    [P0 + B3_OFFSET] = R0;
118   
119    /* save RETS */
120    R0 = RETS;
121    [ P0 + RETS_OFFSET] = R0;
122
123restore:
124    P0 = R1;
125    R1 = [P0 + R1_OFFSET]; 
126    R2 = [P0 + R2_OFFSET];
127    R3 = [P0 + R3_OFFSET];
128    R4 = [P0 + R4_OFFSET];
129    R5 = [P0 + R5_OFFSET];
130    R6 = [P0 + R6_OFFSET];
131    R7 = [P0 + R7_OFFSET];
132       
133    P2 = [P0 + P2_OFFSET];
134    P3 = [P0 + P3_OFFSET];
135    P4 = [P0 + P4_OFFSET];
136    P5 = [P0 + P5_OFFSET];
137
138    /* might have to be placed more to the end */
139    FP = [P0 + FP_OFFSET];
140    SP = [P0 + SP_OFFSET];
141
142    /* save ASTAT */
143    R0 = [P0 + ASTAT_OFFSET];
144    ASTAT = R0;
145
146    /* save Loop Counters */
147    R0 = [P0 + LC0_OFFSET];
148    LC0 = R0;
149    R0 = [P0 + LC1_OFFSET];
150    LC1 = R0;
151
152    /* save Accumulators */
153    R0 = [P0 + A0W_OFFSET];
154    A0.W = R0;
155    R0 = [P0 + A0X_OFFSET];
156    A0.X = R0;
157    R0 = [P0 + A1W_OFFSET];
158    A1.W = R0;
159    R0 = [P0 + A1X_OFFSET];
160    A1.X = R0;
161
162    /* save Index Registers */
163    R0 = [P0 + I0_OFFSET];
164    I0 = R0;
165    R0 = [P0 + I1_OFFSET];
166    I1 = R0;
167    R0 = [P0 + I2_OFFSET];
168    I2 = R0;
169    R0 = [P0 + I3_OFFSET];
170    I3 = R0;
171
172    /* save Modifier Registers */
173    R0 = [P0 + M0_OFFSET];
174    M0 = R0;
175    R0 = [P0 + M1_OFFSET];
176    M1 = R0;
177    R0 = [P0 + M2_OFFSET];
178    M2 = R0;
179    R0 = [P0 + M3_OFFSET];
180    M3 = R0;
181
182    /* save Length Registers */
183    R0 = [P0 + L0_OFFSET];
184    L0 = R0;
185    R0 = [P0 + L1_OFFSET];
186    L1 = R0;
187    R0 = [P0 + L2_OFFSET];
188    L2 = R0;
189    R0 = [P0 + L3_OFFSET];
190    L3 = R0;
191
192    /* Base Registers */
193    R0 = [P0 + B0_OFFSET];
194    B0 = R0;
195    R0 = [P0 + B1_OFFSET];
196    B1 = R0;
197    R0 = [P0 + B2_OFFSET];
198    B2 = R0;
199    R0 = [P0 + B3_OFFSET];
200    B3 = R0;
201
202    /* restore RETS */
203    P1 = [P0 + RETS_OFFSET];
204    RETS = P1;
205
206    /* now restore the P1 + P0 */
207    P1 = [P0 + R1_OFFSET];   
208    P0 = [P0 + P0_OFFSET];
209   
210    rts;
211   
212
213/*
214 *  _CPU_Context_restore
215 *
216 *  This routine is generally used only to restart self in an
217 *  efficient manner.  It may simply be a label in _CPU_Context_switch.
218 *
219 *  NOTE: May be unnecessary to reload some registers.
220 *
221 *  Blackfin Specific Information:
222 *
223 *  none
224 *
225 */
226.globl __CPU_Context_restore
227__CPU_Context_restore:
228    jump restore;
229
230
231
232.globl __ISR_Thread_Dispatch
233__ISR_Thread_Dispatch:
234
235    .extern __Thread_Dispatch
236    R0.l = __Thread_Dispatch;
237    R0.h = __Thread_Dispatch;
238 
239    /* Puts the address of th Thread_Dispatch function on Stack
240     * Where it will be restored to the RTI register
241     */
242    P0 = [FP];
243    /* save the old reti */
244    R1 = [P0+0xc];
245    [P0+0xc] = R0;
246    /*
247     * Overwriting the RETS Register is save because Thread_Dispatch is
248     * disabled when we are between call/link or unlink/rts
249     */
250    [P0+0x8] = R1;
251 
252    /* save old rets */
253 
254    rts;
255
256
257.globl __ISR_Handler
258__ISR_Handler:
259    /* First of all check the Stackpointer and */
260    /* switch to Scratchpad if necessary        */
261     
262    /* save P0 and R0 in the scratchpad */
263    USP = P0;
264   
265    /* load base adress of scratchpad */
266    P0.H = HI(SCRATCH);
267    P0.L = LO(SCRATCH);
268
269    /* if SP is already inside the SCRATCHPAD */
270    CC=SP<P0 (iu)
271    if !CC jump continue;
272   
273    /* set PO to top of scratchpad */   
274    P0.h=HI(SCRATCH_TOP);
275    P0.l=LO(SCRATCH_TOP);
276    /*save the old SP*/
277    [P0] = SP;
278    /*P0 += -4;*/
279    /*set the new Stackpointer*/
280    SP = P0;
281    /*restore the old PO*/
282   
283    /* The Stackpointer is now setup as we want */ 
284    continue:
285    /* restore P0 and save some context */
286    P0 = USP;
287    /* save some state on the isr stack (scratchpad), this enables interrupt nesting */
288    [--SP] = RETI;
289    [--SP] = RETS;
290    [--SP] = ASTAT;
291    [--SP] = FP;
292    FP = SP;
293    [--SP] = (R7:0, P5:0) ;
294   
295   
296    /* Context is saved, now check which Instruction we were executing
297     * If we were between a call and link or between a unlink and rts
298     * we have to disable Thread_Dispatch because correct restore of context after
299     * Thread_Dispatch would not be possible. */
300   
301    P0 = RETI;
302    R0 = W[P0];
303    /* shift 16 bits to the right (select the high nibble ) */
304    /*R0 >>= 16;*/
305   
306    R3 = 0;
307    /* Check if RETI is a LINK instruction */
308    R1.h = HI(0xE800);
309    R1.l = LO(0xE800);
310    CC=R0==R1;
311    if cc jump disablethreaddispatch;
312   
313    /* Check if RETI is a RTS instruction */
314    R1.h = HI(0x0010);
315    R1.l = LO(0x0010);
316    CC=R0==R1;
317    if cc jump disablethreaddispatch;
318   
319    jump afterthreaddispatch;
320   
321    disablethreaddispatch:
322    /*  _Thread_Dispatch_disable_level++   */
323    .extern _Thread_Dispatch_disable_level
324    P0.H = __Thread_Dispatch_disable_level;
325    P0.L = __Thread_Dispatch_disable_level;
326    R0 = [P0];
327    R0 += 1;
328    [P0] = R0;
329    R3 = 1;
330   
331    afterthreaddispatch:
332    /* Put R3 on the stack */
333    [--SP] = R3;
334
335    /* Obtain a bitlist of the pending interrupts. */
336    P0.H = HI(IPEND);
337    P0.L = LO(IPEND);   
338    R1 = [P0];
339   
340    /*
341     * Search through the bit list stored in R0 to find the first enabled
342     * bit. The offset of this bit is the index of the interrupt that is
343     * to be handled.
344     */
345    R0 = -1;
346    intloop:
347        R0 += 1;
348        R1 = ROT R1 by -1;
349        if !cc jump intloop;
350     
351
352    /* pass SP as parameter to the C function */
353    R1 = SP
354
355    /* pass values by register as well as by stack */
356    /* to comply with the c calling conventions    */
357    [--SP] = R0;
358    [--SP] = R1;
359   
360    .extern _ISR_Handler2
361    call    _ISR_Handler2
362
363    /* inc 2 to compensate the passing of arguments */
364    R3 = [SP++];
365    R3 = [SP++];
366    /* check if _Thread_Dispatch_disable_level has been incremented */
367    R3 = [SP++]
368    CC=R3==0
369    if cc jump dont_decrement;
370    .extern _Thread_Dispatch_disable_level
371    P0.H = __Thread_Dispatch_disable_level;
372    P0.L = __Thread_Dispatch_disable_level;
373    R0 = [P0];
374    R0 += -1;
375    [P0] = R0;
376   
377    dont_decrement:
378   
379    (R7:0, P5:0) = [SP++];
380    FP =    [SP++];
381    ASTAT = [SP++];
382    RETS =  [SP++];
383    RETI =  [SP++];
384    /* Interrupts are now disabled again */
385   
386    /*should restore the old stack !!!*/
387    /*if sp now points to SCRATCH_TOP */
388   
389    /* load base adress of scratchpad */
390    USP = P0;
391    P0.H = HI(SCRATCH_TOP);
392    P0.L = LO(SCRATCH_TOP);
393   
394    CC=SP==P0
395    if !cc jump restoreP0
396    /* restore the stack */
397    SP=[P0];
398   
399    restoreP0:
400    P0 = USP;
401       
402    /*now we should be on the old "user-stack" again */
403       
404    /* return from interrupt, will jump to adress stored in RETI */
405    RTI;
406
Note: See TracBrowser for help on using the repository browser.