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

Last change on this file since 623 was 622, checked in by alain, 10 years ago

Introducing a minimal GIET:

  • no virtual memory
  • no conyext switch
  • no system calls
File size: 16.0 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
178    li      $7,     0b011110000000   /* $7 <= PRIO offset */
179    sll     $8,     $13,    2        /* $8 <= local_id*4 */
180    addu    $9,     $7,     $8       /* $9 <= PRIO offset + local_id*4 */
181    la      $27,    seg_xcu_base   
182    addu    $26,    $9,     $27      /* $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      $14,    ($26)            /* $14 <= PRIO register value */
187    mtc2    $0,     $24              /* reset PADDR extension */
188
189    /* test PTI, then HWI, then WTI */
190    andi    $27,    $14,    0x1      /* test bit T in PRIO register */
191    bne     $27,    $0,     _int_PTI /* branch to PTI handler */
192    andi    $27,    $14,    0x2      /* test bit W in PRIO register */
193    bne     $27,    $0,     _int_HWI /* branch to HWI handler */
194    andi    $27,    $14,    0x4      /* test bit W in PRIO register */
195    bne     $27,    $0,     _int_WTI /* branch to IPI handler */
196   
197    /* exit interrupt handler: restore registers */
198_int_restore:
199    .set noat
200    lw      $1,     4*4($29)         /* restore $1 */
201    .set at
202    lw      $2,     4*5($29)         /* restore $2 */
203    lw      $3,     4*6($29)         /* restore $3 */
204    lw      $4,     4*7($29)         /* restore $4 */
205    lw      $5,     4*8($29)         /* restore $5 */
206    lw      $6,     4*9($29)         /* restore $6 */
207    lw      $7,     4*10($29)        /* restore $7 */
208    lw      $8,     4*11($29)        /* restore $8 */
209    lw      $9,     4*12($29)        /* restore $9 */
210    lw      $10,    4*13($29)        /* restore $10 */
211    lw      $11,    4*14($29)        /* restore $11 */
212    lw      $12,    4*15($29)        /* restore $12 */
213    lw      $13,    4*16($29)        /* restore $13 */
214    lw      $14,    4*17($29)        /* restore $14 */
215    lw      $15,    4*18($29)        /* restore $15 */
216    lw      $24,    4*19($29)        /* restore $24 */
217    lw      $25,    4*20($29)        /* restore $25 */
218    lw      $31,    4*21($29)        /* restore $31 */
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_int_PTI:
225    srl     $26,    $14,    6        /* $26 <= (PRIO>>6  = PTI index) */
226    j       _int_call_isr
227    nop
228
229_int_HWI:
230    srl     $26,    $14,    14       /* $26 <= (PRIO>>14 = HWI index) */
231    j       _int_call_isr
232    nop
233
234_int_WTI:
235    srl     $26,    $14,    22       /* $26 <= (PRIO>>22 = WTI index) */
236    j       _int_call_isr
237    nop
238   
239    /* Call the relevant ISR */
240_int_call_isr:
241    andi    $26,    $26,    0x7C     /* $26 <= interrupt_index * 4 */
242    la      $27,    _interrupt_vector
243    addu    $26,    $26,    $27
244    lw      $26,    ($26)            /* read ISR address */
245    jalr    $26                      /* call ISR */
246    nop
247    j       _int_restore
248    nop
249
250/* The default ISR is called when no specific ISR has been installed */
251/* in the interrupt vector. It simply displays a message on TTY0     */
252
253isr_default:
254    addiu   $29,    $29,    -20     /* get space in stack */
255    sw      $31,    16($29)         /* to save the return address */
256    la      $4,     _msg_default    /* $4 <= string address */
257    addi    $5,     $0,     36      /* $5 <= string length */
258    li      $6,     0               /* $6 <= TTY0 */
259    jal     _tty_write
260    lw      $31,    16($29)         /* restore return address */
261    addiu   $29,    $29,    20      /* free space */
262    jr      $31                     /* returns to interrupt handler */
263
264/****************************************************************
265*  Interrupt Vector Table (indexed by interrupt index)
266*  32 words corresponding to 32 ISR addresses
267****************************************************************/
268_interrupt_vector:
269    .word isr_default   /* ISR 0 */
270    .word isr_default   /* ISR 1 */
271    .word isr_default   /* ISR 2 */
272    .word isr_default   /* ISR 3 */
273    .word isr_default   /* ISR 4 */
274    .word isr_default   /* ISR 5 */
275    .word isr_default   /* ISR 6 */
276    .word isr_default   /* ISR 7 */
277    .word isr_default   /* ISR 8 */
278    .word isr_default   /* ISR 9 */
279    .word isr_default   /* ISR 10 */
280    .word isr_default   /* ISR 11 */
281    .word isr_default   /* ISR 12 */
282    .word isr_default   /* ISR 13 */
283    .word isr_default   /* ISR 14 */
284    .word isr_default   /* ISR 15 */
285    .word isr_default   /* ISR 16 */
286    .word isr_default   /* ISR 17 */
287    .word isr_default   /* ISR 18 */
288    .word isr_default   /* ISR 19 */
289    .word isr_default   /* ISR 20 */
290    .word isr_default   /* ISR 21 */
291    .word isr_default   /* ISR 22 */
292    .word isr_default   /* ISR 23 */
293    .word isr_default   /* ISR 24 */
294    .word isr_default   /* ISR 25 */
295    .word isr_default   /* ISR 26 */
296    .word isr_default   /* ISR 27 */
297    .word isr_default   /* ISR 28 */
298    .word isr_default   /* ISR 29 */
299    .word isr_default   /* ISR 30 */
300    .word isr_default   /* ISR 31 */
301
302    .end _int_handler
303
304/****************************************************************
305*    Exception Handler
306* Same code for all fatal exceptions :
307* Print the exception type and the values of EPC & BAR
308* on the TTY correspondintg to the processor PROCID,
309* and the user program is killed.
310****************************************************************/
311    .ent _exc_handler
312
313_exc_handler:
314_cause_bp:
315_cause_ukn:
316_cause_ri:
317_cause_ovf:
318_cause_adel:
319_cause_ades:
320_cause_ibe:
321_cause_dbe:
322_cause_cpu:
323    mfc0    $26,    $13             /* $26 <= CR */
324    andi    $26,    $26,    0x3C    /* $26 <= _cause_index * 4 */
325    la      $27,    _mess_causes    /* mess_cause table base address */
326    addu    $27,    $26,    $27     /* $26 <= message base address */
327
328    /* take the lock on TTY0 */
329    li      $4,     0
330    jal     _tty_get_lock
331    nop
332
333    /* display exception type */
334    lw      $4,     ($27)           /* $4 <= message address */
335    li      $5,     36              /* $5 <= message length */
336    li      $6,     0               /* $6 <= TTY0 */
337    jal     _tty_write               
338    nop
339
340    /* display EPC value */
341    la      $4,     _msg_epc        /* $4 <= message address */
342    li      $5,     8               /* $5 <= message length */
343    li      $6,     0               /* $6 <= TTY0 */
344    jal     _tty_write           
345    nop
346   
347    mfc0    $4,     $14             /* $4 <= EPC value */
348    la      $5,     _itoa_buffer    /* $5 <= buffer address */
349    addiu   $5,     $5,     2       /* skip 0x prefix */
350    jal     _itoa_hex               /* fill buffer */
351    nop
352
353    la      $4,     _itoa_buffer    /* $4 <= buffer address */
354    li      $5,     10              /* $5 <= buffer length */
355    li      $6,     0               /* $6 <= TTY0 */
356    jal     _tty_write
357    nop
358
359    /* display BAR value */
360    la      $4,     _msg_bar        /* $4 <= message address */
361    li      $5,     8               /* $5 <= message length */
362    li      $6,     0               /* $6 <= TTY0 */
363    jal     _tty_write
364    nop
365
366    mfc0    $4,     $8              /* $4 <= BAR value */
367    la      $5,     _itoa_buffer    /* $5 <= buffer address */
368    addiu   $5,     $5,     2       /* skip 0x prefix */
369    jal     _itoa_hex               /* fill buffer */
370    nop
371
372    la      $4,     _itoa_buffer    /* $4 <= message address */
373    li      $5,     10              /* $5 <= message length */
374    li      $6,     0               /* $6 <= TTY0 */
375    jal     _tty_write
376    nop
377
378   
379    /* release the lock on TTY0 */
380    li      $4,     0
381    jal     _tty_get_lock
382    nop
383
384    j       _exit                   /* kill user program */
385
386/* Exceptions Messages table (indexed by XCODE)  */
387_mess_causes:
388    .word _msg_ukncause
389    .word _msg_ukncause
390    .word _msg_ukncause
391    .word _msg_ukncause
392    .word _msg_adel
393    .word _msg_ades
394    .word _msg_ibe
395    .word _msg_dbe
396    .word _msg_ukncause
397    .word _msg_bp
398    .word _msg_ri
399    .word _msg_cpu
400    .word _msg_ovf
401    .word _msg_ukncause
402    .word _msg_ukncause
403    .word _msg_ukncause
404
405/********************************************************************
406*    All messages
407* Messages length are fixed : 8 or 36 characters...
408********************************************************************/
409_msg_bar:        .asciiz "\nBAR  = "
410_msg_epc:        .asciiz "\nEPC  = "
411_msg_default:    .asciiz "\n\n  !!! Default ISR  !!!           \n"
412_msg_uknsyscall: .asciiz "\n\n  !!! Undefined System Call !!!  \n"
413_msg_ukncause:   .asciiz "\n\nException : strange unknown cause\n"
414_msg_adel:       .asciiz "\n\nException : illegal read address \n"
415_msg_ades:       .asciiz "\n\nException : illegal write address\n"
416_msg_ibe:        .asciiz "\n\nException : inst bus error       \n"
417_msg_dbe:        .asciiz "\n\nException : data bus error       \n"
418_msg_bp:         .asciiz "\n\nException : breakpoint           \n"
419_msg_ri:         .asciiz "\n\nException : reserved instruction \n"
420_msg_ovf:        .asciiz "\n\nException : arithmetic overflow  \n"
421_msg_cpu:        .asciiz "\n\nException : illegal coproc access\n"
422
423    .end _exc_handler
424
425
Note: See TracBrowser for help on using the repository browser.