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

4.8
Last change on this file since b72e847b was c55364c4, checked in by Joel Sherrill <joel.sherrill@…>, on 09/10/07 at 22:24:57

2007-09-10 Alain Schaefer <alani@…>

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