source: trunk/softs/giet_tsar/giet.S @ 778

Last change on this file since 778 was 744, checked in by cfuguet, 10 years ago

giet_tsar: using CLUSTER_IO constant in stdio functions

  • Erasing also extra end-of-line spaces
File size: 17.4 KB
Line 
1/********************************************************************************
2*       File : giet.S
3*       Author : Alain Greiner
4*       Date : 15/01/2014
5*********************************************************************************
6* This is a very simple Interrupts/Exception/Traps handler for a generic
7* multi-clusters / multi-processors TSAR architecture (up to 256 clusters,
8* up to 4  processors per cluster).
9* The physical address is 40 bits, and the 8 MSB bits A[39:32] define the
10* cluster index.
11********************************************************************************/
12
13#include "hard_config.h"
14
15    .section .giet,"ax",@progbits
16    .align 2
17    .global _interrupt_vector
18
19    .extern seg_xcu_base
20    .extern seg_tty_base
21
22    .extern _procid
23    .extern _proctime
24    .extern _tty_write
25    .extern _tty_read
26    .extern _tty_read_irq
27    .extern _locks_read
28    .extern _locks_write
29    .extern _exit
30    .extern _fb_sync_write
31    .extern _fb_sync_read
32    .extern _ioc_write
33    .extern _ioc_read
34    .extern _ioc_completed
35    .extern _itoa_hex
36    .extern _barrier_init
37    .extern _barrier_wait
38
39    .ent _giet
40
41/****************************************************************
42*    Cause Table (indexed by the Cause register)
43****************************************************************/
44tab_causes:
45    .word _int_handler  /* 0000 : external interrupt */
46    .word _cause_ukn    /* 0001 : undefined exception */
47    .word _cause_ukn    /* 0010 : undefined exception */
48    .word _cause_ukn    /* 0011 : undefined exception */
49    .word _cause_adel   /* 0100 : illegal address read exception */
50    .word _cause_ades   /* 0101 : illegal address write exception */
51    .word _cause_ibe    /* 0110 : instruction bus error exception */
52    .word _cause_dbe    /* 0111 : data bus error exception */
53    .word _sys_handler  /* 1000 : system call */
54    .word _cause_bp     /* 1001 : breakpoint exception */
55    .word _cause_ri     /* 1010 : illegal codop exception */
56    .word _cause_cpu    /* 1011 : illegal coprocessor access */
57    .word _cause_ovf    /* 1100 : arithmetic overflow exception */
58    .word _cause_ukn    /* 1101 : undefined exception */
59    .word _cause_ukn    /* 1110 : undefined exception */
60    .word _cause_ukn    /* 1111 : undefined exception */
61
62    .space 320
63
64/****************************************************************
65*    Entry point (base + 0x180)
66****************************************************************/
67_giet:
68    mfc0    $27,    $13             /* Cause Register analysis */
69    la      $26,    seg_kcode_base  /* $26 <= tab_causes */
70    andi    $27,    $27,    0x3c
71    addu    $26,    $26,    $27     /* $26 <= &tab_causes[XCODE] */
72    lw      $26,    ($26)
73    jr      $26                     /* Jump to tab_causes[XCODE] */
74
75    .end _giet
76
77/****************************************************************
78*   System Call Handler
79*
80* As the GIET_TSAR does not support system calls,
81* an error message is displayed on TTY0, the program is killed.
82****************************************************************/
83    .ent _sys_handler
84
85_sys_handler:
86    la      $4,     _msg_uknsyscall /* $4 <= message address */
87    li      $5,    36               /* $5 <= message length */
88    li      $6,    0                /* $6 <= TTY0 */
89    jal     _tty_write              /* print unknown message */
90    nop
91
92    la      $4,     _msg_epc        /* $4 <= message address */
93    li      $5,    8                /* $5 <= message length */
94    li      $6,    0                /* $6 <= TTY0 */
95    jal     _tty_write              /* print EPC message */
96    nop
97
98    mfc0    $4,     $14             /* $4 <= EPC */
99    la      $5,     _itoa_buffer    /* $5 <= buffer address */
100    addiu   $5,     $5,     2       /* skip the 0x prefix */
101    jal     _itoa_hex               /* fill the buffer */
102    nop
103
104    la      $4,     _itoa_buffer    /* $4 <= buffer address */
105    li      $5,     10              /* $5 <= buffer length */
106    li      $6,    0                /* $6 <= TTY0 */
107    jal     _tty_write              /* print EPC value */
108    nop
109
110    j       _exit                   /* end of program */
111
112_itoa_buffer: .ascii "0x00000000"
113
114    .align 2
115
116    .end _sys_handler
117
118/****************************************************************
119*   Interrupt Handler
120* This simple interrupt handler cannot be interrupted.
121* It uses the SoCLib VCI_XICU component.
122* It makes the assumption that there is only one interrupt per
123* entry in the interrupt vector (it can be PTI, HWI, or WTI).
124* In case of a multi-clusters architecture, it exist one XCU
125* per cluster, and the base address of the ICU segment depends
126* on both the cluster_xy and the proc_id:
127* - base_address = seg_xcu_base + (32*local_id) + (4G*cluster_xy)
128* - cluster_xy = proc_id / NB_PROCS_MAX
129* - local_id   = proc_id % NB_PROCS_MAX
130* If no active interrupt is found in the PRIO register,
131* nothing is done.
132* The interrupt vector (32 ISR addresses array stored at
133* _interrupt_vector address) is initialised with the default
134* ISR address. The actual ISR addresses are supposed to be written
135* in the interrupt vector array by the boot code.
136* All non persistant registers, such as $1 to $15, and $24 to $25,
137* as well as register $31 and EPC, are saved in the interrupted
138* program stack, before calling the Interrupt Service Routine.
139* These registers can be used by the ISR code.
140***************************************************************/
141    .ent _int_handler
142
143_int_handler:
144    addiu   $29,    $29,    -23*4   /* stack space reservation */
145    .set noat
146    sw      $1,     4*4($29)        /* save $1 */
147    .set at
148    sw      $2,     4*5($29)        /* save $2 */
149    sw      $3,     4*6($29)        /* save $3 */
150    sw      $4,     4*7($29)        /* save $4 */
151    sw      $5,     4*8($29)        /* save $5 */
152    sw      $6,     4*9($29)        /* save $6 */
153    sw      $7,     4*10($29)       /* save $7 */
154    sw      $8,     4*11($29)       /* save $8 */
155    sw      $9,     4*12($29)       /* save $9 */
156    sw      $10,    4*13($29)       /* save $10 */
157    sw      $11,    4*14($29)       /* save $11 */
158    sw      $12,    4*15($29)       /* save $12 */
159    sw      $13,    4*16($29)       /* save $13 */
160    sw      $14,    4*17($29)       /* save $14 */
161    sw      $15,    4*18($29)       /* save $15 */
162    sw      $24,    4*19($29)       /* save $24 */
163    sw      $25,    4*20($29)       /* save $25 */
164    sw      $31,    4*21($29)       /* save $31 */
165    mfc0    $27,    $14
166    sw      $27,    4*22($29)       /* save EPC */
167
168    /* XICU PRIO register address computation         */
169    /* It depends on both the cluster_xy & local_id,  */
170    /* and we must use the physical address extension */
171    mfc0    $10,    $15,    1        /* $10 <= proc_id                                 */
172    andi    $10,    $10,    0x3FF    /* at most 1024 processors                        */
173    li      $11,    NB_PROCS_MAX
174    divu    $10,    $11
175    mflo    $12                      /* $12 <= cluster_xy                              */
176    mfhi    $13                      /* $13 <= local_id                                */
177    la      $14,    seg_xcu_base     /* $14 <= seg_xcu_base                            */
178
179    li      $7,     0b011110000000   /* $7 <= PRIO offset                              */
180    sll     $8,     $13,    2        /* $8 <= local_id*4                               */
181    addu    $9,     $7,     $8       /* $9 <= PRIO offset + local_id*4                 */
182    addu    $26,    $9,     $14      /* $26 <= seg_icu_base + PRIO offset + local_id*4 */
183
184    /* XCU[cluster_xy] access to get PRIO register value                               */
185    mtc2    $12,    $24              /* set PADDR extension                            */
186    lw      $15,    0($26)           /* $15 <= PRIO register value                     */
187    mtc2    $0,     $24              /* reset PADDR extension                          */
188
189    /* test PTI, then HWI, then WTI                                                    */
190    andi    $27,    $15,    0x1      /* test bit T in PRIO register                    */
191    bne     $27,    $0,     _int_PTI /* branch to PTI handler                          */
192    andi    $27,    $15,    0x2      /* test bit W in PRIO register                    */
193    bne     $27,    $0,     _int_HWI /* branch to HWI handler                          */
194    andi    $27,    $15,    0x4      /* test bit W in PRIO register                    */
195    bne     $27,    $0,     _int_WTI /* branch to WTI handler                          */
196
197    /* exit interrupt handler: restore registers */
198_int_restore:
199    .set noat
200    lw      $1,     4*4($29)
201    .set at
202    lw      $2,     4*5($29)
203    lw      $3,     4*6($29)
204    lw      $4,     4*7($29)
205    lw      $5,     4*8($29)
206    lw      $6,     4*9($29)
207    lw      $7,     4*10($29)
208    lw      $8,     4*11($29)
209    lw      $9,     4*12($29)
210    lw      $10,    4*13($29)
211    lw      $11,    4*14($29)
212    lw      $12,    4*15($29)
213    lw      $13,    4*16($29)
214    lw      $14,    4*17($29)
215    lw      $15,    4*18($29)
216    lw      $24,    4*19($29)
217    lw      $25,    4*20($29)
218    lw      $31,    4*21($29)
219    lw      $27,    4*22($29)        /* get EPC */
220    addiu   $29,    $29,    23*4     /* restore SP */
221    mtc0    $27,    $14              /* restore EPC */
222    eret                             /* exit GIET */
223
224    /* The PTI handler get PTI index, */
225    /* acknowledge the PTI register   */
226    /* and call the corresponding ISR */
227_int_PTI:
228    srl     $26,    $15,    6        /* $26 <= PRIO >> 6             */
229    andi    $26,    $26,    0x7C     /* $26 <= PTI_INDEX * 4         */
230    addi    $27,    $14,    0x180    /* $27 <= &PTI_ACK[0]           */
231    add     $27,    $27,    $26      /* $27 <= &PTI_ACK[PTI_INDEX]   */
232    lw      $0,     ($27)            /* acknowledge XICU PTI         */
233    la      $27,    _interrupt_vector
234    addu    $26,    $26,    $27
235    lw      $26,    ($26)            /* read ISR address             */
236    jalr    $26                      /* call ISR                     */
237    nop
238    j       _int_restore             /* return from INT handler      */
239    nop
240
241    /* The HWI handler get HWI index  */
242    /* and call the corresponding ISR */
243_int_HWI:
244    srl     $26,    $15,    14       /* $26 <= PRIO >> 14            */
245    andi    $26,    $26,    0x7C     /* $26 <= HWI_INDEX * 4         */
246    la      $27,    _interrupt_vector
247    addu    $26,    $26,    $27      /* $26 <= &ISR[HWI_INDEX        */
248    lw      $26,    ($26)            /* read ISR address             */
249    jalr    $26                      /* call ISR                     */
250    nop
251    j       _int_restore             /* return from INT handler      */
252    nop
253
254    /* The WTI handler get WTI index, */
255    /* acknowledge the WTI register   */
256    /* and call the corresponding ISR */
257_int_WTI:
258    srl     $26,    $15,    22       /* $26 <= PRIO >> 22            */
259    andi    $26,    $26,    0x7C     /* $26 <= WTI_INDEX * 4         */
260    add     $27,    $14,    $26      /* $27 <= &WTI_REG[WTI_INDEX]   */
261    lw      $0,     ($27)            /* acknowledge XICU WTI         */
262    la      $27,    _interrupt_vector
263    addu    $26,    $26,    $27      /* $26 <= &ISR[WTI_INDEX]       */
264    lw      $26,    ($26)            /* read ISR address             */
265    jalr    $26                      /* call ISR                     */
266    nop
267    j       _int_restore             /* return from INT handler */
268    nop
269
270/* The default ISR is called when no specific ISR has been installed */
271/* in the interrupt vector. It simply displays a message on TTY0     */
272
273isr_default:
274    addiu   $29,    $29,    -20     /* get space in stack */
275    sw      $31,    16($29)         /* to save the return address */
276    la      $4,     _msg_default    /* $4 <= string address */
277    addi    $5,     $0,     36      /* $5 <= string length */
278    li      $6,     0               /* $6 <= TTY0 */
279    jal     _tty_write
280    lw      $31,    16($29)         /* restore return address */
281    addiu   $29,    $29,    20      /* free space */
282    jr      $31                     /* returns to interrupt handler */
283
284/****************************************************************
285*  Interrupt Vector Table (indexed by interrupt index)
286*  32 words corresponding to 32 ISR addresses
287****************************************************************/
288_interrupt_vector:
289    .word isr_default   /* ISR 0 */
290    .word isr_default   /* ISR 1 */
291    .word isr_default   /* ISR 2 */
292    .word isr_default   /* ISR 3 */
293    .word isr_default   /* ISR 4 */
294    .word isr_default   /* ISR 5 */
295    .word isr_default   /* ISR 6 */
296    .word isr_default   /* ISR 7 */
297    .word isr_default   /* ISR 8 */
298    .word isr_default   /* ISR 9 */
299    .word isr_default   /* ISR 10 */
300    .word isr_default   /* ISR 11 */
301    .word isr_default   /* ISR 12 */
302    .word isr_default   /* ISR 13 */
303    .word isr_default   /* ISR 14 */
304    .word isr_default   /* ISR 15 */
305    .word isr_default   /* ISR 16 */
306    .word isr_default   /* ISR 17 */
307    .word isr_default   /* ISR 18 */
308    .word isr_default   /* ISR 19 */
309    .word isr_default   /* ISR 20 */
310    .word isr_default   /* ISR 21 */
311    .word isr_default   /* ISR 22 */
312    .word isr_default   /* ISR 23 */
313    .word isr_default   /* ISR 24 */
314    .word isr_default   /* ISR 25 */
315    .word isr_default   /* ISR 26 */
316    .word isr_default   /* ISR 27 */
317    .word isr_default   /* ISR 28 */
318    .word isr_default   /* ISR 29 */
319    .word isr_default   /* ISR 30 */
320    .word isr_default   /* ISR 31 */
321
322    .end _int_handler
323
324/****************************************************************
325*    Exception Handler
326* Same code for all fatal exceptions :
327* Print the exception type and the values of EPC & BAR
328* on the TTY correspondintg to the processor PROCID,
329* and the user program is killed.
330****************************************************************/
331    .ent _exc_handler
332
333_exc_handler:
334_cause_bp:
335_cause_ukn:
336_cause_ri:
337_cause_ovf:
338_cause_adel:
339_cause_ades:
340_cause_ibe:
341_cause_dbe:
342_cause_cpu:
343    mfc0    $26,    $13             /* $26 <= CR */
344    andi    $26,    $26,    0x3C    /* $26 <= _cause_index * 4 */
345    la      $27,    _mess_causes    /* mess_cause table base address */
346    addu    $27,    $26,    $27     /* $26 <= message base address */
347
348    /* take the lock on TTY0 */
349    li      $4,     0
350    jal     _tty_get_lock
351    nop
352
353    /* display exception type */
354    lw      $4,     ($27)           /* $4 <= message address */
355    li      $5,     36              /* $5 <= message length */
356    li      $6,     0               /* $6 <= TTY0 */
357    jal     _tty_write
358    nop
359
360    /* display EPC value */
361    la      $4,     _msg_epc        /* $4 <= message address */
362    li      $5,     8               /* $5 <= message length */
363    li      $6,     0               /* $6 <= TTY0 */
364    jal     _tty_write
365    nop
366
367    mfc0    $4,     $14             /* $4 <= EPC value */
368    la      $5,     _itoa_buffer    /* $5 <= buffer address */
369    addiu   $5,     $5,     2       /* skip 0x prefix */
370    jal     _itoa_hex               /* fill buffer */
371    nop
372
373    la      $4,     _itoa_buffer    /* $4 <= buffer address */
374    li      $5,     10              /* $5 <= buffer length */
375    li      $6,     0               /* $6 <= TTY0 */
376    jal     _tty_write
377    nop
378
379    /* display BAR value */
380    la      $4,     _msg_bar        /* $4 <= message address */
381    li      $5,     8               /* $5 <= message length */
382    li      $6,     0               /* $6 <= TTY0 */
383    jal     _tty_write
384    nop
385
386    mfc0    $4,     $8              /* $4 <= BAR value */
387    la      $5,     _itoa_buffer    /* $5 <= buffer address */
388    addiu   $5,     $5,     2       /* skip 0x prefix */
389    jal     _itoa_hex               /* fill buffer */
390    nop
391
392    la      $4,     _itoa_buffer    /* $4 <= message address */
393    li      $5,     10              /* $5 <= message length */
394    li      $6,     0               /* $6 <= TTY0 */
395    jal     _tty_write
396    nop
397
398
399    /* release the lock on TTY0 */
400    li      $4,     0
401    jal     _tty_get_lock
402    nop
403
404    j       _exit                   /* kill user program */
405
406/* Exceptions Messages table (indexed by XCODE)  */
407_mess_causes:
408    .word _msg_ukncause
409    .word _msg_ukncause
410    .word _msg_ukncause
411    .word _msg_ukncause
412    .word _msg_adel
413    .word _msg_ades
414    .word _msg_ibe
415    .word _msg_dbe
416    .word _msg_ukncause
417    .word _msg_bp
418    .word _msg_ri
419    .word _msg_cpu
420    .word _msg_ovf
421    .word _msg_ukncause
422    .word _msg_ukncause
423    .word _msg_ukncause
424
425/********************************************************************
426*    All messages
427* Messages length are fixed : 8 or 36 characters...
428********************************************************************/
429_msg_bar:        .asciiz "\nBAR  = "
430_msg_epc:        .asciiz "\nEPC  = "
431_msg_default:    .asciiz "\n\n  !!! Default ISR  !!!           \n"
432_msg_uknsyscall: .asciiz "\n\n  !!! Undefined System Call !!!  \n"
433_msg_ukncause:   .asciiz "\n\nException : strange unknown cause\n"
434_msg_adel:       .asciiz "\n\nException : illegal read address \n"
435_msg_ades:       .asciiz "\n\nException : illegal write address\n"
436_msg_ibe:        .asciiz "\n\nException : inst bus error       \n"
437_msg_dbe:        .asciiz "\n\nException : data bus error       \n"
438_msg_bp:         .asciiz "\n\nException : breakpoint           \n"
439_msg_ri:         .asciiz "\n\nException : reserved instruction \n"
440_msg_ovf:        .asciiz "\n\nException : arithmetic overflow  \n"
441_msg_cpu:        .asciiz "\n\nException : illegal coproc access\n"
442
443    .end _exc_handler
444
445
Note: See TracBrowser for help on using the repository browser.