source: branches/v4/softs/giet_tsar/giet.s @ 457

Last change on this file since 457 was 158, checked in by alain, 14 years ago

Introducing the three sub-directories in the softs directory:

  • giet_tsar
  • soft_filter_giet
  • soft_transpose_giet
File size: 31.5 KB
Line 
1/*********************************************************************************
2*    File : giet.s
3*    Author : Franck Wajsburt & Alain Greiner & Joel Porquet
4*    Date : 2009 - 2010
5**********************************************************************************
6*    Interruption/Exception/Trap Handler for MIPS32 processor
7*    The base address of the segment containing this code
8*    MUST be 0x80000000, in order to have the entry point
9*    at address 0x80000180 !!!
10*    All messages are printed on the TTY defined by the processor ID.
11**********************************************************************************
12*    History :
13*    15/09/2009 : The GIET entry point has been modified to comply with
14*        the MIPS32 specification : 0x80000180
15*    5/10/2009  : The syscall handler has been modified to comply with the
16*        MIPS32 specification : the value stored in EPC register is the
17*        syscall instruction address => it must be incremented by 4
18*        to obtain the return address.
19*    15/10/2009 : The Interrupt handler has been modified to comply with the
20*        VCI_ICU specification : The IRQ index is obtained by a read
21*        to (icu_base_address + 16).
22*    26/10/2009 : The interrupt handler has been modified to support
23*        multi-processors architectures with one ICU per processor.
24*        Finally, the mfc0 instruction uses now the select parameter
25*        to comply with the MIPS32 specification when accessing the
26*        processor_id (mtfc0 $x, $15, 1)
27*    08/11/2009 : The syscall handler has been extended to support 32 values
28*        for the syscall index, and to enable interrupts when processing
29*        a system call.
30*        Five new syscalls have been introduced to access the frame buffer
31*        Three new syscalls have been introduced to access the block device
32*        The two syscalls associated to the DMA have been removed.
33*    18/11/2009 : The syscall handler has been modified to save the SR in
34*        the stack before enabling interrupts.
35*    15/03/2010 : replace the itoa_print assembler function by the itoa_hex()
36*        function defined in the syscalls.c file.
37*    10/04/2010 : modify the interrupt handler to use the new ICU component
38*        supporting up to 8 output IRQs for 8 processors.
39*        The active IRQ index is obtained as ICU[32*PROC_ID+16].
40*    12/09/2010 : The ctx_switch functionhas been included in this file to
41*        simplify the compilation process.
42*   25/09/2010 : add '.end' directive to end the _giet function
43*        and modify the 'sharp' comment character into the regular "slash
44*        asterix ... asterix slash" comment syntax
45*   27/09/2010 : respect stack convention with 4 minimum slots before calling
46*        C functions
47*   28/09/2010 : Save all the non-persistant registers in the int_handler
48*   02/02/2011 : Introduce the "segment_increment" parameter in the interrupt
49*        handler to support clusterised multi-processing.
50*        Introducing the barrier_init() & barrier_wait() system calls.
51*   04/04/2011 : introducing the system call proc_num() 
52*   12/04/2011 : modifying the _int_handler to support the XICU component in
53*        multi_clusters/multi-processors architectures:
54*        the XICU base address depends the cluster_id and the PRIO register
55*        address depends on the local_id.
56**********************************************************************************/
57
58    .section .giet,"ax",@progbits
59    .align 2
60    .global _interrupt_vector    # makes interrupt_vector an external symbol
61
62    .extern seg_icu_base
63    .extern seg_tty_base
64    .extern NB_CLUSTERS
65    .extern NB_PROCS
66
67    .extern isr_default
68
69    .extern _procid
70    .extern _proctime
71    .extern _tty_write
72    .extern _tty_read
73    .extern _tty_read_irq
74    .extern _timer_write
75    .extern _timer_read
76    .extern _icu_write
77    .extern _icu_read
78    .extern _gcd_write
79    .extern _gcd_read
80    .extern _locks_read
81    .extern _locks_write
82    .extern _exit
83    .extern _fb_sync_write
84    .extern _fb_sync_read
85    .extern _fb_write
86    .extern _fb_read
87    .extern _fb_completed
88    .extern _ioc_write
89    .extern _ioc_read
90    .extern _ioc_completed
91    .extern _itoa_hex
92    .extern _barrier_init
93    .extern _barrier_wait
94
95    .ent _giet
96
97/***************************************************************
98*    Cause Table (indexed by the Cause register)
99***************************************************************/
100tab_causes:
101    .word _int_handler  # 0000 : external interrupt
102    .word _cause_ukn    # 0001 : undefined exception
103    .word _cause_ukn    # 0010 : undefined exception
104    .word _cause_ukn    # 0011 : undefined exception
105    .word _cause_adel   # 0100 : illegal address read exception
106    .word _cause_ades   # 0101 : illegal address write exception
107    .word _cause_ibe    # 0110 : instruction bus error exception
108    .word _cause_dbe    # 0111 : data bus error exception
109    .word _sys_handler  # 1000 : system call
110    .word _cause_bp     # 1001 : breakpoint exception
111    .word _cause_ri     # 1010 : illegal codop exception
112    .word _cause_cpu    # 1011 : illegal coprocessor access
113    .word _cause_ovf    # 1100 : arithmetic overflow exception
114    .word _cause_ukn    # 1101 : undefined exception
115    .word _cause_ukn    # 1110 : undefined exception
116    .word _cause_ukn    # 1111 : undefined exception
117
118    .space 320
119
120/***************************************************************
121*    Entry point (at address 0x80000180)
122***************************************************************/
123_giet:
124    mfc0    $27,    $13             # Cause Register analysis
125    lui     $26,    0x8000          # $26 <= tab_causes
126    andi    $27,    $27,    0x3c
127    addu    $26,    $26,    $27
128    lw      $26,    ($26)
129    jr      $26                     # Jump indexed by CR
130    .end _giet
131
132/****************************************************************
133*   System Call Handler
134* A system call is handled as a special function call.
135*   - $2 contains the system call index (< 16).
136*   - $3 is used to store the syscall address
137*   - $4, $5, $6, $7 contain the arguments values.
138*   - The return address (EPC) iand the SR are saved in the stack.
139*   - Interrupts are enabled before branching to the syscall.
140*   - All syscalls must return to the syscall handler.
141*   - $2, $3, $4, $5, $6, $7 as well as $26 & $27 can be modified.
142*
143* In case of undefined system call, an error message displays
144* the value of EPC on the TTY corresponding to the processor,
145* and the user program is killed.
146****************************************************************/
147_sys_handler:
148    addiu   $29,    $29,    -24     # 2 slots for SR&EPC, 4 slots for args passing
149    mfc0    $26,    $12             # load SR
150    sw      $26,    16($29)         # save it in the stack
151    mfc0    $27,    $14             # load EPC
152    addiu   $27,    $27,    4       # increment EPC for return address
153    sw      $27,    20($29)         # save it in the stack
154
155    andi    $26,    $2,     0x1F    # $26 <= syscall index (i < 32)
156    sll     $26,    $26,    2       # $26 <= index * 4
157    la      $27,    tab_syscalls    # $27 <= &tab_syscalls[0]
158    addu    $27,    $27,    $26     # $27 <= &tab_syscalls[i]
159    lw      $3,     0($27)          # $3  <= syscall address
160
161    li      $27,    0xFFFFFFED      # Mask for UM & EXL bits
162    mfc0    $26,    $12             # $26 <= SR
163    and     $26,    $26,    $27     # UM = 0 / EXL = 0
164    mtc0    $26,    $12             # interrupt enabled
165    jalr    $3                      # jump to the proper syscall
166    mtc0    $0,     $12             # interrupt disbled
167
168    lw      $26,    16($29)         # load SR from stack
169    mtc0    $26,    $12             # restore SR
170    lw      $26,    20($29)         # load EPC from stack
171    mtc0    $26,    $14             # restore EPC
172    addiu   $29,    $29,     24     # restore stack pointer
173    eret                            # exit GIET
174
175_sys_ukn:                           # undefined system call
176    la      $4,     msg_uknsyscall  # $4 <= message address
177    li      $5,    36               # $5 <= message length
178    jal     _tty_write              # print unknown message
179
180    la      $4,     msg_epc         # $4 <= message address
181    li      $5,    8                # $5 <= message length
182    jal     _tty_write              # print EPC message
183
184    mfc0    $4,     $14             # $4 <= EPC
185    la      $5,     itoa_buffer     # $5 <= buffer address
186    addiu   $5,     $5,     2       # skip the 0x prefix
187    jal     _itoa_hex               # fill the buffer
188
189    la      $4,     itoa_buffer     # $4 <= buffer address
190    li      $5,     10              # $5 <= buffer length
191    jal     _tty_write              # print EPC value
192
193    j       _exit                   # end of program
194
195itoa_buffer: .ascii "0x00000000"
196
197    .align 2
198
199/****************************************************************
200* System Call Table (indexed by syscall index) 
201****************************************************************/
202tab_syscalls:
203    .word _procid           # 0x00
204    .word _proctime         # 0x01
205    .word _tty_write        # 0x02
206    .word _tty_read         # 0x03
207    .word _timer_write      # 0x04
208    .word _timer_read       # 0x05
209    .word _gcd_write        # 0x06
210    .word _gcd_read         # 0x07
211    .word _icu_write        # 0x08
212    .word _icu_read         # 0x09
213    .word _tty_read_irq     # 0x0A
214    .word _sys_ukn          # 0x0B
215    .word _locks_write      # 0x0C
216    .word _locks_read       # 0x0D
217    .word _exit             # 0x0E
218    .word _procnumber       # 0x0F
219    .word _fb_sync_write    # 0x10
220    .word _fb_sync_read     # 0x11
221    .word _fb_write         # 0x12
222    .word _fb_read          # 0x13
223    .word _fb_completed     # 0x14
224    .word _ioc_write        # 0x15
225    .word _ioc_read         # 0x16
226    .word _ioc_completed    # 0x17
227    .word _barrier_init     # 0x18
228    .word _barrier_wait     # 0x19
229    .word _sys_ukn          # 0x1A
230    .word _sys_ukn          # 0x1B
231    .word _sys_ukn          # 0x1C
232    .word _sys_ukn          # 0x1D
233    .word _sys_ukn          # 0x1E
234    .word _sys_ukn          # 0x1F
235
236/******************************************************************
237*    Interrupt Handler
238* This simple interrupt handler cannot be interrupted.
239* It uses an external ICU component (Interrupt Controler Unit)
240* that concentrates up to 32 interrupts lines to a single IRQ
241* line that can be connected to any of the 6 MIPS IT inputs.
242* This component returns the highest priority active interrupt index
243* (smaller indexes have the highest priority).
244*
245* In case of a multi-clusters architecture, it exist one ICU
246* per cluster. The base address of the ICU segment depends on both
247* the cluster_id and the proc_id:
248* - icu_base_address = seg_icu_base + (32 * local_id) +
249*                    (cluster_increment * cluster _id)
250* - cluster_id = proc_id / NB_PROCS
251* - local_id = proc_id % NB_PROCS
252* - cluster_increment = 4G / NB_CLUSTERS
253*
254* The interrupt handler reads the XICU PRIO register,
255* using the offset 16.
256* This component returns the highest priority interrupt index
257* (smaller indexes have the highest priority).
258* Any value larger than 31 means "no active interrupt", and
259* the default ISR (that does nothing) is executed.
260* The interrupt vector (32 ISR addresses array stored at
261* _interrupt_vector address) is initialised with the default
262* ISR address. The actual ISR addresses are supposed to be written
263* in the interrupt vector array by the boot code.
264* All non persistant registers, such as $1 to $15, and $24 to $25,
265* as well as register $31 and EPC, are saved in the interrupted
266* program stack, before calling the Interrupt Service Routine.
267* These registers can be used by the ISR code.
268*******************************************************************/
269_int_handler:
270    addiu   $29,    $29,    -23*4   # stack space reservation
271    .set noat
272    sw      $1,     4*4($29)        # save $1
273    .set at
274    sw      $2,     4*5($29)        # save $2
275    sw      $3,     4*6($29)        # save $3
276    sw      $4,     4*7($29)        # save $4
277    sw      $5,     4*8($29)        # save $5
278    sw      $6,     4*9($29)        # save $6
279    sw      $7,     4*10($29)       # save $7
280    sw      $8,     4*11($29)       # save $8
281    sw      $9,     4*12($29)       # save $9
282    sw      $10,    4*13($29)       # save $10
283    sw      $11,    4*14($29)       # save $11
284    sw      $12,    4*15($29)       # save $12
285    sw      $13,    4*16($29)       # save $13
286    sw      $14,    4*17($29)       # save $14
287    sw      $15,    4*18($29)       # save $15
288    sw      $24,    4*19($29)       # save $24
289    sw      $25,    4*20($29)       # save $25
290    sw      $31,    4*21($29)       # save $31
291    mfc0    $27,    $14
292    sw      $27,    4*22($29)       # save EPC
293
294    # XICU PRIO register address computation (depending on cluster_id & local_id)
295    mfc0    $10,    $15,    1       # $10 <= proc_id
296    andi    $10,    $10,    0x3FF   # at most 1024 processors
297    la      $11,    NB_PROCS        # $11 <= NB_PROCS
298    divu    $10,    $11
299    mflo    $12                     # $12 <= cluster_id
300    mfhi    $13                     # $13 <= local_id
301    la      $11,    NB_CLUSTERS     # $11 <= NB_CLUSTERS
302    li      $14,    0x80000000     
303    divu    $14,    $11
304    mflo    $15 
305    sll     $15,    $15,    1       # $15 <= cluster_increment = 4G / NB_CLUSTERS
306    multu   $15,    $12
307    mflo    $6                      # $6 <= cluster_increment * cluster_id
308    li      $7,     0b011110000000  # $7 <= PRIO offset
309    sll     $8,     $13,    2       # $8 <= local_id*4
310    addu    $9,     $7,     $8      # $9 <= PRIO offset + local_id*4
311    la      $27,    seg_icu_base   
312    addu    $26,    $9,     $27     # $26 <= seg_icu_base + PRIO offset + local_id*4
313    addu    $26,    $26,    $6      # $26 <= seg_icu_base + increment*cluster_id + PRIO offset + local_id*4
314
315    # XICU access and interrupt vector access
316    lw      $26,    ($26)           # $26 <= PRIO register value
317    andi    $27,    $26,    0x2     # test bit HWI active
318    beq     $27,    $0,     restore # do nothing if no active IRQ
319    srl     $26,    $26,    14      # $26 <= $26 >> 14
320    andi    $26,    $26,    0x7C    # $26 <= interrupt_index * 4
321    la      $27,    _interrupt_vector
322    addu    $26,    $26,    $27
323    lw      $26,    ($26)           # read ISR address
324    jalr    $26                     # call ISR
325restore:
326    .set noat
327    lw      $1,     4*4($29)        # restore $1
328    .set at
329    lw      $2,     4*5($29)        # restore $2
330    lw      $3,     4*6($29)        # restore $3
331    lw      $4,     4*7($29)        # restore $4
332    lw      $5,     4*8($29)        # restore $5
333    lw      $6,     4*9($29)        # restore $6
334    lw      $7,     4*10($29)       # restore $7
335    lw      $8,     4*11($29)       # restore $8
336    lw      $9,     4*12($29)       # restore $9
337    lw      $10,    4*13($29)       # restore $10
338    lw      $11,    4*14($29)       # restore $11
339    lw      $12,    4*15($29)       # restore $12
340    lw      $13,    4*16($29)       # restore $13
341    lw      $14,    4*17($29)       # restore $14
342    lw      $15,    4*18($29)       # restore $15
343    lw      $24,    4*19($29)       # restore $24
344    lw      $25,    4*20($29)       # restore $25
345    lw      $31,    4*21($29)       # restore $31
346    lw      $27,    4*22($29)       # return address (EPC)
347    addiu   $29,    $29,    23*4    # restore stack pointer
348    mtc0    $27,    $14             # restore EPC
349    eret                            # exit GIET
350
351/* The default ISR is called when no specific ISR has been installed in the
352 interrupt vector. It simply displays a message on TTY 0. */
353
354isr_default:
355    addiu   $29,    $29,    -20     # get space in stack
356    sw      $31,    16($29)         # to save the return address
357    la      $4,     msg_default     # $4 <= string address
358    addi    $5,     $0,     36      # $5 <= string length
359    jal     _tty_write              # print
360    lw      $31,    16($29)         # restore return address
361    addiu   $29,    $29,    20      # free space
362    jr      $31                     # returns to interrupt handler
363
364/*****************************************************
365 Interrupt Vector Table (indexed by interrupt index)
366  32 words corresponding to 32 ISR addresses
367******************************************************/
368_interrupt_vector:
369    .word isr_default   # ISR 0
370    .word isr_default   # ISR 1
371    .word isr_default   # ISR 2
372    .word isr_default   # ISR 3
373    .word isr_default   # ISR 4
374    .word isr_default   # ISR 5
375    .word isr_default   # ISR 6
376    .word isr_default   # ISR 7
377    .word isr_default   # ISR 8
378    .word isr_default   # ISR 9
379    .word isr_default   # ISR 10
380    .word isr_default   # ISR 11
381    .word isr_default   # ISR 12
382    .word isr_default   # ISR 13
383    .word isr_default   # ISR 14
384    .word isr_default   # ISR 15
385    .word isr_default   # ISR 16
386    .word isr_default   # ISR 17
387    .word isr_default   # ISR 18
388    .word isr_default   # ISR 19
389    .word isr_default   # ISR 20
390    .word isr_default   # ISR 21
391    .word isr_default   # ISR 22
392    .word isr_default   # ISR 23
393    .word isr_default   # ISR 24
394    .word isr_default   # ISR 25
395    .word isr_default   # ISR 26
396    .word isr_default   # ISR 27
397    .word isr_default   # ISR 28
398    .word isr_default   # ISR 29
399    .word isr_default   # ISR 30
400    .word isr_default   # ISR 31
401
402/***********************************************************
403*    Exception Handler
404* Same code for all fatal exceptions :
405* Print the exception type and the values of EPC & BAR
406* on the TTY correspondintg to the processor PROCID,
407* and the user program is killed.
408***********************************************************/
409_cause_bp:
410_cause_ukn:
411_cause_ri:
412_cause_ovf:
413_cause_adel:
414_cause_ades:
415_cause_ibe:
416_cause_dbe:
417_cause_cpu:
418    mfc0    $26,    $13             # $26 <= CR
419    andi    $26,    $26,    0x3C    # $26 <= _cause_index * 4
420    la      $27,    mess_causes     # mess_cause table base address
421    addu    $27,    $26,    $27     # pointer on the message base address
422
423    lw      $4,     ($27)           # $4 <= message address
424    li      $5,     36              # $5 <= message length
425    jal     _tty_write              # print message cause
426
427    la      $4,     msg_epc         # $4 <= message address
428    li      $5,     8               # $5 <= message length
429    jal     _tty_write              # print message EPC
430
431    mfc0    $4,     $14             # $4 <= EPC value
432    la      $5,     itoa_buffer     # $5 <= buffer address
433    addiu   $5,     $5,     2       # skip 0x prefix
434    jal     _itoa_hex               # fill buffer
435
436    la      $4,     itoa_buffer     # $4 <= buffer address
437    li      $5,     10              # $5 <= buffer length
438    jal     _tty_write              # print EPC value
439
440    la      $4,     msg_bar         # $4 <= mesage address
441    li      $5,     8               # $5 <= message length
442    jal     _tty_write              # print message BAR
443
444    mfc0    $4,     $8              # $4 <= BAR value
445    la      $5,     itoa_buffer     # $5 <= buffer address
446    addiu   $5,     $5,     2       # skip 0x prefix
447    jal     _itoa_hex               # fill buffer
448
449    la      $4,     itoa_buffer     # $4 <= mesage address
450    li      $5,     10              # $5 <= message length
451    jal     _tty_write              # print BAR value
452
453    j       _exit                   # end program
454
455# Exceptions Messages table (indexed by CAUSE) 
456mess_causes:
457    .word msg_ukncause
458    .word msg_ukncause
459    .word msg_ukncause
460    .word msg_ukncause
461    .word msg_adel
462    .word msg_ades
463    .word msg_ibe
464    .word msg_dbe
465    .word msg_ukncause
466    .word msg_bp
467    .word msg_ri
468    .word msg_cpu
469    .word msg_ovf
470    .word msg_ukncause
471    .word msg_ukncause
472    .word msg_ukncause
473
474/*****************************************************************
475*    All messages
476* Messages length are fixed : 8 or 36 characters...
477*****************************************************************/
478msg_bar:        .asciiz "\nBAR  = "
479msg_epc:        .asciiz "\nEPC  = "
480msg_default:    .asciiz "\n\n  !!! Default ISR  !!!           \n"
481msg_uknsyscall: .asciiz "\n\n  !!! Undefined System Call !!!  \n"
482msg_ukncause:   .asciiz "\n\nException : strange unknown cause\n"
483msg_adel:       .asciiz "\n\nException : illegal read address \n"
484msg_ades:       .asciiz "\n\nException : illegal write address\n"
485msg_ibe:        .asciiz "\n\nException : inst bus error       \n"
486msg_dbe:        .asciiz "\n\nException : data bus error       \n"
487msg_bp:         .asciiz "\n\nException : breakpoint           \n"
488msg_ri:         .asciiz "\n\nException : reserved instruction \n"
489msg_ovf:        .asciiz "\n\nException : arithmetic overflow  \n"
490msg_cpu:        .asciiz "\n\nException : illegal coproc access\n"
491    .align 2
492
493
494/***************************************************************************
495*        _ctx_switch
496*   The _ctx_switch function performs a context switch between the
497*   current task and another task.
498*   It can be used in a multi-processor architecture, with the assumption
499*   that the tasks are statically allocated to processors.
500*   The max number of processorsi is 8, and the max number of tasks is 4.
501*   The scheduling policy is very simple : For each processor, the task index
502*   is incremented,  modulo the number of tasks allocated to the processor.
503*
504*   It has no argument, and no return value.
505*
506*   It uses three global variables:
507*    - _current_task_array :  an array of 8 task index:
508*      (index of the task actually running on each processor)
509*    - _task_number_array : an array of 8 numbers:
510*      (the number of tasks allocated to each processor)
511*       - _task_context_array : an array of 32 task contexts:
512*      (at most 8 processors / each processor can run up to 4 tasks)
513*   A task context is an array of 64 words = 256 bytes.
514*   It is indexed by m = (proc_id*4 + task_id)
515*   It contains copies of the processor registers.
516*   As much as possible a register is stored at the index defined by its number
517*   ( for example, $8 is saved in ctx[8]).
518*   The exception are :
519*   $0 is not saved since always 0
520*   $26, $27 are not saved since not used by the task
521*
522*   0*4(ctx) SR    8*4(ctx) $8    16*4(ctx) $16   24*4(ctx) $24   32*4(ctx) EPC
523*   1*4(ctx) $1    9*4(ctx) $9    17*4(ctx) $17   25*4(ctx) $25   33*4(ctx) CR
524*   2*4(ctx) $2   10*4(ctx) $10   18*4(ctx) $18   26*4(ctx) LO    34*4(ctx) reserved
525*   3*4(ctx) $3   11*4(ctx) $11   19*4(ctx) $19   27*4(ctx) HI    35*4(ctx) reserved
526*   4*4(ctx) $4   12*4(ctx) $12   20*4(ctx) $20   28*4(ctx) $28   36*4(ctx) reserved
527*   5*4(ctx) $5   13*4(ctx) $13   21*4(ctx) $21   29*4(ctx) $29   37*4(ctx) reserved
528*   6*4(ctx) $6   14*4(ctx) $14   22*4(ctx) $22   30*4(ctx) $30   38*4(ctx) reserved
529*   7*4(ctx) $7   15*4(ctx) $15   23*4(ctx) $23   31*4(ctx) $31   39*4(ctx) reserved
530*
531*   The return address contained in $31 is saved in the _current task context
532*   (in the ctx[31] slot), and the function actually returns to the address contained
533*   in the ctx[31] slot of the new task context.
534*
535*   Caution : This function is intended to be used with periodic interrupts.
536*   It can be directly called by the OS, but interrupts must be disabled before calling.
537***************************************************************************************/
538
539    .section .ksave
540
541    .global _task_context_array # initialised in reset.s
542    .global _current_task_array # initialised in reset.s
543    .global _task_number_array  # initialised in reset.s
544
545_task_context_array:    # 32 contexts : indexed by (proc_id*4 + task_id)
546    .space  8192
547
548_current_task_array:    # 8 words : indexed by the proc_id
549    .word   0           # _current_task_array[0] <= 0
550    .word   0           # _current_task_array[1] <= 0
551    .word   0           # _current_task_array[2] <= 0
552    .word   0           # _current_task_array[3] <= 0
553    .word   0           # _current_task_array[4] <= 0
554    .word   0           # _current_task_array[5] <= 0
555    .word   0           # _current_task_array[6] <= 0
556    .word   0           # _current_task_array[7] <= 0
557
558_task_number_array:     # 8 words : indexed by the proc_id
559    .word   1           # _task_number_array[0] <= 1
560    .word   1           # _task_number_array[1] <= 1
561    .word   1           # _task_number_array[2] <= 1
562    .word   1           # _task_number_array[3] <= 1
563    .word   1           # _task_number_array[4] <= 1
564    .word   1           # _task_number_array[5] <= 1
565    .word   1           # _task_number_array[6] <= 1
566    .word   1           # _task_number_array[7] <= 1
567
568/***************************************************************************************/
569
570    .section .switch
571
572    .global _ctx_switch # makes it an external symbol
573    .align  2
574
575_ctx_switch:
576
577    # test if more than one task on the processor
578
579    mfc0    $26,    $15,    1
580    andi    $26,    $26,    0x7         # $26 <= proc_id
581    sll     $26,    $26,    2           # $26 <= 4*proc_id
582    la      $27,    _task_number_array  # $27 <= base address of _task_number_array
583    addu    $27,    $27,    $26         # $27 <= _task_number_array + 4*proc_id
584    lw      $27,    ($27)               # $27 <= task number
585    addi    $26,    $27,    -1          # $26 <= _task_number - 1
586    bnez    $26,    do_it               # 0 if only one task
587    jr      $31                         # return
588
589    # save _current task context
590
591do_it:
592    mfc0    $26,    $15,    1
593    andi    $26,    $26,    0x7         # $26 <= proc_id
594    sll     $26,    $26,    2           # $26 <= 4*proc_id
595    la      $27,    _current_task_array # $27 <= base address of _current_task_array
596    addu    $27,    $27,    $26         # $27 <= _current_task_array + 4*proc_id
597    lw      $26,    ($27)               # $26 <= current task index
598    sll     $26,    $26,    8           # $26 <= 256*task_id
599    la      $27,    _task_context_array # $27 <= base address of context array
600    addu    $27,    $27,    $26         # $27 <= _task_context_array + 256*task_id
601    mfc0    $26,    $15,    1
602    andi    $26,    $26,    0x7         # $26 <= proc_id
603    sll     $26,    $26,    10          # $26 <= 1024*proc_id
604    addu    $27,    $27,    $26         # $27 <= taxk_context_array + 256*(proc_id*4 + task_id)
605
606    mfc0    $26,    $12         # $26 <= SR
607    sw      $26,    0*4($27)    # ctx[0] <= SR
608    .set noat
609    sw      $1,     1*4($27)    # ctx[1] <= $1
610    .set at
611    sw      $2,     2*4($27)    # ctx[2] <= $2
612    sw      $3,     3*4($27)    # ctx[3] <= $3
613    sw      $4,     4*4($27)    # ctx[4] <= $4
614    sw      $5,     5*4($27)    # ctx[5] <= $5
615    sw      $6,     6*4($27)    # ctx[6] <= $6
616    sw      $7,     7*4($27)    # ctx[7] <= $7
617    sw      $8,     8*4($27)    # ctx[8] <= $8
618    sw      $9,     9*4($27)    # ctx[9] <= $9
619    sw      $10,    10*4($27)   # ctx[10] <= $10
620    sw      $11,    11*4($27)   # ctx[11] <= $11
621    sw      $12,    12*4($27)   # ctx[12] <= $12
622    sw      $13,    13*4($27)   # ctx[13] <= $13
623    sw      $14,    14*4($27)   # ctx[14] <= $14
624    sw      $15,    15*4($27)   # ctx[15] <= $15
625    sw      $16,    16*4($27)   # ctx[16] <= $16
626    sw      $17,    17*4($27)   # ctx[17] <= $17
627    sw      $18,    18*4($27)   # ctx[18] <= $18
628    sw      $19,    19*4($27)   # ctx[19] <= $19
629    sw      $20,    20*4($27)   # ctx[20] <= $20
630    sw      $21,    21*4($27)   # ctx[21] <= $21
631    sw      $22,    22*4($27)   # ctx[22] <= $22
632    sw      $23,    23*4($27)   # ctx[23] <= $23
633    sw      $24,    24*4($27)   # ctx[24] <= $24
634    sw      $25,    25*4($27)   # ctx[25] <= $25
635    mflo    $26
636    sw      $26,    26*4($27)   # ctx[26] <= LO
637    mfhi    $26
638    sw      $26,    27*4($27)   # ctx[27] <= H1
639    sw      $28,    28*4($27)   # ctx[28] <= $28
640    sw      $29,    29*4($27)   # ctx[29] <= $29
641    sw      $30,    30*4($27)   # ctx[30] <= $30
642    sw      $31,    31*4($27)   # ctx[31] <= $31
643    mfc0    $26,    $14
644    sw      $26,    32*4($27)   # ctx[32] <= EPC
645    mfc0    $26,    $13
646    sw      $26,    33*4($27)   # ctx[33] <= CR
647
648    # select  the new task
649
650    mfc0    $15,    $15,    1
651    andi    $15,    $15,    0x7         # $15 <= proc_id
652    sll     $16,    $15,    2           # $16 <= 4*proc_id
653    la      $17,    _current_task_array # $17 <= base address of _current_task_array
654    addu    $17,    $17,    $16         # $17 <= _current_task_array + 4*proc_id
655    lw      $18,    ($17)               # $18 <= _current task index
656    la      $19,    _task_number_array  # $19 <= base address of _task_number_array
657    addu    $19,    $19,    $16         # $19 <= _task_number_array + 4*proc_id
658    lw      $20,    ($19)               # $20 <= max = number of tasks
659    addiu   $18,    $18,    1           # $18 <= new task index
660    sub     $2,     $18,    $20         # test modulo max
661    bne     $2,     $0,     no_wrap
662    add     $18,    $0,     $0          # $18 <= new task index
663no_wrap:
664    sw      $18,    ($17)               # update _current_task_array
665
666    # restore next task context
667
668    sll     $19,    $18,    8           # $19 <= 256*task_id
669    la      $27,    _task_context_array # $27 <= base address of context array
670    addu    $27,    $27,    $19         # $27 <= _task_context_array + 256*task_id
671    sll     $19,    $15,    10          # $19 <= 1024*proc_id
672    addu    $27,    $27,    $19         # $27 <= _task_context_array + 256*(proc_id*4 + task_id)
673
674    lw      $26,    0*4($27)
675    mtc0    $26,    $12                 # restore SR
676    .set noat
677    lw      $1,     1*4($27)            # restore $1
678    .set at
679    lw      $2,     2*4($27)            # restore $2
680    lw      $3,     3*4($27)            # restore $3
681    lw      $4,     4*4($27)            # restore $4
682    lw      $5,     5*4($27)            # restore $5
683    lw      $6,     6*4($27)            # restore $6
684    lw      $7,     7*4($27)            # restore $7
685    lw      $8,     8*4($27)            # restore $8
686    lw      $9,     9*4($27)            # restore $9
687    lw      $10,    10*4($27)           # restore $10
688    lw      $11,    11*4($27)           # restore $11
689    lw      $12,    12*4($27)           # restore $12
690    lw      $13,    13*4($27)           # restore $13
691    lw      $14,    14*4($27)           # restore $14
692    lw      $15,    15*4($27)           # restore $15
693    lw      $16,    16*4($27)           # restore $16
694    lw      $17,    17*4($27)           # restore $17
695    lw      $18,    18*4($27)           # restore $18
696    lw      $19,    19*4($27)           # restore $19
697    lw      $20,    20*4($27)           # restore $20
698    lw      $21,    21*4($27)           # restore $21
699    lw      $22,    22*4($27)           # restore $22
700    lw      $23,    23*4($27)           # restore $23
701    lw      $24,    24*4($27)           # restore $24
702    lw      $25,    25*4($27)           # restore $25
703    lw      $26,    26*4($27)
704    mtlo    $26                         # restore LO
705    lw      $26,    27*4($27)
706    mthi    $26                         # restore HI
707    lw      $28,    28*4($27)           # restore $28
708    lw      $29,    29*4($27)           # restore $29
709    lw      $30,    30*4($27)           # restore $30
710    lw      $31,    31*4($27)           # restore $31
711    lw      $26,    32*4($27)
712    mtc0    $26,    $14                 # restore EPC
713    lw      $26,    33*4($27)
714    mtc0    $26,    $13                 # restore CR
715
716    jr      $31                         # returns to caller
717
718/* Local Variables:
719   tab-width: 4;
720   c-basic-offset: 4;
721   c-file-offsets:((innamespace . 0)(inline-open . 0));
722   indent-tabs-mode: nil;
723   End: */
724
725/* vim: set filetype=asm expandtab shiftwidth=4 tabstop=4 softtabstop=4: */
726
Note: See TracBrowser for help on using the repository browser.