.kdata
__m1_:	.asciiz "  Exception "
__m2_:	.asciiz " occurred and ignored\n"
__m3_:	.asciiz " Interrupt\n"
__m5__: .ascii	" E' stato premuto il carattere "
Carattere: .asciiz "\n\n"
_brk_msg: .asciiz " (code in instruction)"
__e0_:	.asciiz "  [Interrupt] "
__e1_:	.asciiz	"  [TLB]"
__e2_:	.asciiz	"  [TLB]"
__e3_:	.asciiz	"  [TLB]"
__e4_:	.asciiz	"  [Address error in inst/data fetch] "
__e5_:	.asciiz	"  [Address error in store] "
__e6_:	.asciiz	"  [Bad instruction address] "
__e7_:	.asciiz	"  [Bad data address] "
__e8_:	.asciiz	"  [Error in syscall] "
__e9_:	.asciiz	"  [Breakpoint] "
__e10_:	.asciiz	"  [Reserved instruction] "
__e11_:	.asciiz	""
__e12_:	.asciiz	"  [Arithmetic overflow] "
__e13_:	.asciiz	"  [Trap] "
__e14_:	.asciiz	""
__e15_:	.asciiz	"  [Floating point] "
__e16_:	.asciiz	""
__e17_:	.asciiz	""
__e18_:	.asciiz	"  [Coproc 2]"
__e19_:	.asciiz	""
__e20_:	.asciiz	""
__e21_:	.asciiz	""
__e22_:	.asciiz	"  [MDMX]"
__e23_:	.asciiz	"  [Watch]"
__e24_:	.asciiz	"  [Machine check]"
__e25_:	.asciiz	""
__e26_:	.asciiz	""
__e27_:	.asciiz	""
__e28_:	.asciiz	""
__e29_:	.asciiz	""
__e30_:	.asciiz	"  [Cache]"
__e31_:	.asciiz	""
__excp:	.word __e0_, __e1_, __e2_, __e3_, __e4_, __e5_, __e6_, __e7_, __e8_, __e9_
	.word __e10_, __e11_, __e12_, __e13_, __e14_, __e15_, __e16_, __e17_, __e18_,
	.word __e19_, __e20_, __e21_, __e22_, __e23_, __e24_, __e25_, __e26_, __e27_,
	.word __e28_, __e29_, __e30_, __e31_

save0: .word 0
save1: .word 0

.ktext 0x80000180 		# kernel text segment (inizia a 0x80000180) 
.set noat				#disabilita il warning sull'uso del registro $at 
move  $k1, $at			# salvataggio $at (usato nelle pseudo-instruzioni dall’exception handler)
.set at					
sw      $v0, save0		# salvataggio $v0 (usato da myExceptionHandler.s)
sw      $a0, save1		# salvataggio $a0 (usato da myExceptionHandler.s)
						#non serve salvare $k0 e $k1 perche' per convenzione riservati

mfc0  $k0, $13 			# copia nel registro $k0 della CPU, il registro $13 (Cause register) del coprocessor 0
srl $a0, $k0, 2			#codice della causa dell’eccezione da $k0 e mette in $a0 facendo shift right di 2
andi  $a0, $k0, 0x007c    	# Riconosce e distingue tra eccezioni e interrupt
 				# Exception mask: 0x007c = 0000 0000 0111 1100
bgtz  $a0, Excp_ret       		# salta a Excp_ret se e’ una eccezione, cioe’ non è un 			# interrupt da periferica (XXXX XXXX X000 00XX)

#se non e’ un’eccezione, cioe’ e’ un interrupt 
li     $v0, 4 			# Stampa Interrupt rilevato
la    $a0, __m3_   		#__m3_: .asciiz " Interrupt\n"
syscall           	
# print "  Interrupt “
# Gestione dell'Interrupt XXXX non trattata in questo esempio
IntXXXX:
#...

# Da inserire nel Exceptions.s nella gestione degli interrupt
IntKbd:
  andi  $a0, $k0, 0x0100           
	# Receiver mask: 0x0100 = 0000 0001 0000 0000
  beq   $a0, $0,  EndIntKbd       
	# branch se e' interrupt ma non di Receiver

  # E' interrupt del Receiver, quindi ...
  # Stampa le info sull'interrupt
  li    	$v0, 4
  la    	$a0, __m5_
  syscall           		

 # DISABILITA Interruzioni dal Receiver (tastiera)
  lw    $a0, 0xFFFF0000	# Leggi attuale Receiver Control
  andi  $a0, $a0, 0xFFFD	# Azzera bit 1 = INT enable
  sw    $a0, 0xFFFF0000	# Scrivi nuovo Receiver Control

 # DISABILITA Interrupt Receiver nella CPU
  mfc0  $a0, $12		# Leggi il CPU Status Reg.
  andi  $a0, $a0, 0xFEFF	# Azzera il bit INT del Receiver
  mtc0  $a0, $12		# Scrivi il nuovo CPU Status Reg.

  # Gestione del char digitato
  lw    $a0, 0xFFFF0004	# prelevo il carattere dal Data Reg. 
#  sw    $a0, BuffKbd 		# e lo metto nel buffer comune
  sw    $a0, Carattere 		# e lo metto nel buffer comune

EndIntKbd:
 # ABILITA interrupt della CPU
  mfc0  $t0, $12           	# Leggi CPU Status register
  ori   $t0, $t0, 1         	# abilita in generale gli INT
  ori   $t0, $t0, 0x100    	# abilita il bit INT del Receiver
  mtc0  $t0, $12            	# Scrivi nuovo CPU Status register

  # ABILITA Interrupt dal Receiver (tastiera)
  lw    $t1, 0xFFFF0000    	# Leggi attuale Receiver Control
  ori   $t1, $t1, 2         	# abilita il bit 1 (= INT enable)
  sw    $t1, 0xFFFF0000   	# scrivi nuovo Receiver Control

EndIntXXXX:

# Rientro dalla gestione degli interrupt
mtc0   $0, $13 		# Si resetta il Cause register ($13)

# Ripristino registri salvati
  lw       $v0, save0
  lw       $a0, save1
  .set noat				#disabilita il warning sull'uso del registro $at 
  move  $at, $k1
  .set at				#disabilita il warning sull'uso del registro $at 
  
		# Preleva l'indirizzo di ritorno
		# e salta all'indirizzo di ritorno (NB qui senza incrementare il valore in EPC)
eret               	# Return from exception handler

# Gestione delle eccezioni
Excp_ret:                     		# Stampa le info sulla eccezione
  li       $v0, 4
  la      $a0, __m1_
  syscall          		 # print "  Exception "

  li       $v0, 1
  srl     $a0, $k0, 2 		# shift right logical - estrae il Codice eccezione
  andi  $a0, $a0, 0x1f
  syscall           		# print Codice eccezione

  li      $v0, 4
  lw    $a0, __excp($k0)
  syscall           		# print stringa def eccezione

  srl     $k0, $k0, 2 		# estrae il Codice eccezione perche’ era in $a0 che e’ stato sovracritto

Excp_Aritm:
    bne $k0, 0xc, End_Excp_Aritm      	# non e' eccezione per overflow aritmetico
    li     $v0, 4                       # syscall 4 (print_str)
    la    $a0, __e12_               	# eccezione overflow aritmetico
    syscall   
   j       End_Excp_Hnd

End_Excp_Aritm:		# Fine gestione overflow aritmetico

End_Excp_Hnd:		# Epilogo del gestore delle Eccezioni
  mtc0    $0, $13 		# Si resetta il Cause register

  lw       $v0, save0	# Si ripristina i registri salvati
  lw       $a0, save1
.set noat				#disabilita il warning sull'uso del registro $at 
  move  $at, $k1
.set at				#disabilita il warning sull'uso del registro $at 

  			# Si preleva l'indirizzo di ritorno e salta all'indirizzo di ritorno
  mfc0   $k0, $14    	# carica EPC in $k0
  addi    $k0, $k0, 4 	# Ritorna alla istruzione successiva
  mtc0   $k0, $14
  eret           		# Return from exception handler (all’istruzione indicata da EPC)

# Standard startup code, good as a minimal "exception handler".i
#  Invoke the routine "main" with arguments:
#	main(argc, argv, envp)
#
	.text
	.globl __start
__start:
	lw $a0 0($sp)		# argc
	addiu $a1 $sp 4		# argv
	addiu $a2 $a1 4		# envp
	sll $v0 $a0 2
	addu $a2 $a2 $v0
	jal main
	nop

	li $v0 10
	syscall			# syscall 10 (exit)

	nop #just to speparate this code from user's code below