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

4.104.114.84.9
Last change on this file since fbf8301 was fbf8301, checked in by Ralf Corsepius <ralf.corsepius@…>, on Nov 8, 2006 at 8:42:45 AM

2006-11-08 Ralf Corsépius <ralf.corsepius@…>

  • cpu_asm.S: Re-add HI, LO.
  • Property mode set to 100644
File size: 9.1 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#include <rtems/bfin/bfin.h>
23
24#define LO(con32) ((con32) & 0xFFFF)
25#define HI(con32) (((con32) >> 16) & 0xFFFF)
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);
271
272    /* if SP is already inside the SCRATCHPAD */
273    CC=SP<P0 (iu)
274    if !CC jump continue;
275   
276    /* set PO to top of scratchpad */   
277    P0.h=HI(SCRATCH_TOP);
278    P0.l=LO(SCRATCH_TOP);
279    /*save the old SP*/
280    [P0] = SP;
281    /*P0 += -4;*/
282    /*set the new Stackpointer*/
283    SP = P0;
284    /*restore the old PO*/
285   
286    /* The Stackpointer is now setup as we want */ 
287    continue:
288    /* restore P0 and save some context */
289    P0 = USP;
290    /* save some state on the isr stack (scratchpad), this enables interrupt nesting */
291    [--SP] = RETI;
292    [--SP] = RETS;
293    [--SP] = ASTAT;
294    [--SP] = FP;
295    FP = SP;
296    [--SP] = (R7:0, P5:0) ;
297   
298   
299    /* Context is saved, now check which Instruction we were executing
300     * If we were between a call and link or between a unlink and rts
301     * we have to disable Thread_Dispatch because correct restore of context after
302     * Thread_Dispatch would not be possible. */
303   
304    P0 = RETI;
305    R0 = W[P0];
306    /* shift 16 bits to the right (select the high nibble ) */
307    /*R0 >>= 16;*/
308   
309    R3 = 0;
310    /* Check if RETI is a LINK instruction */
311    R1.h = HI(0xE800);
312    R1.l = LO(0xE800);
313    CC=R0==R1;
314    if cc jump disablethreaddispatch;
315   
316    /* Check if RETI is a RTS instruction */
317    R1.h = HI(0x0010);
318    R1.l = LO(0x0010);
319    CC=R0==R1;
320    if cc jump disablethreaddispatch;
321   
322    jump afterthreaddispatch;
323   
324    disablethreaddispatch:
325    /*  _Thread_Dispatch_disable_level++   */
326    .extern _Thread_Dispatch_disable_level
327    P0.H = __Thread_Dispatch_disable_level;
328    P0.L = __Thread_Dispatch_disable_level;
329    R0 = [P0];
330    R0 += 1;
331    [P0] = R0;
332    R3 = 1;
333   
334    afterthreaddispatch:
335    /* Put R3 on the stack */
336    [--SP] = R3;
337
338    /* Obtain a bitlist of the pending interrupts. */
339    P0.H = HI(IPEND);
340    P0.L = LO(IPEND);   
341    R1 = [P0];
342   
343    /*
344     * Search through the bit list stored in R0 to find the first enabled
345     * bit. The offset of this bit is the index of the interrupt that is
346     * to be handled.
347     */
348    R0 = -1;
349    intloop:
350        R0 += 1;
351        R1 = ROT R1 by -1;
352        if !cc jump intloop;
353     
354
355    /* pass SP as parameter to the C function */
356    R1 = SP
357
358    /* pass values by register as well as by stack */
359    /* to comply with the c calling conventions    */
360    [--SP] = R0;
361    [--SP] = R1;
362   
363    .extern _ISR_Handler2
364    call    _ISR_Handler2
365
366    /* inc 2 to compensate the passing of arguments */
367    R3 = [SP++];
368    R3 = [SP++];
369    /* check if _Thread_Dispatch_disable_level has been incremented */
370    R3 = [SP++]
371    CC=R3==0
372    if cc jump dont_decrement;
373    .extern _Thread_Dispatch_disable_level
374    P0.H = __Thread_Dispatch_disable_level;
375    P0.L = __Thread_Dispatch_disable_level;
376    R0 = [P0];
377    R0 += -1;
378    [P0] = R0;
379   
380    dont_decrement:
381   
382    (R7:0, P5:0) = [SP++];
383    FP =    [SP++];
384    ASTAT = [SP++];
385    RETS =  [SP++];
386    RETI =  [SP++];
387    /* Interrupts are now disabled again */
388   
389    /*should restore the old stack !!!*/
390    /*if sp now points to SCRATCH_TOP */
391   
392    /* load base adress of scratchpad */
393    USP = P0;
394    P0.H = HI(SCRATCH_TOP);
395    P0.L = LO(SCRATCH_TOP);
396   
397    CC=SP==P0
398    if !cc jump restoreP0
399    /* restore the stack */
400    SP=[P0];
401   
402    restoreP0:
403    P0 = USP;
404       
405    /*now we should be on the old "user-stack" again */
406       
407    /* return from interrupt, will jump to adress stored in RETI */
408    RTI;
409
Note: See TracBrowser for help on using the repository browser.