  NAME    main
        
  PUBLIC  __iar_program_start
        
  SECTION .intvec : CODE (2)
  CODE32
        
__iar_program_start
  B       initialisation        ; Reset
  
  ; ÉCRIVEZ ICI VOTRE VECTEUR D'INTERRUPTIONS
  ; Le processeur doit effectuer un saut à l'étiquette moninterruption
  ; lorsqu'une interruption FIQ est déclenchée.
  ; Si, lorsque vous lancez le programme, IAR vous affiche une erreur
  ; disant "Trying to set a breakpoint outside linked memory at address 0x8",
  ; c'est que vous n'avez pas codé ce vecteur correctement!

ProcessusCourant        DC32     0              ; Contient le numéro du processus en cours

  SECTION .text : CODE (2)
  CODE32

moninterruption
  ; Dans cette interruption, les registres R8 à R15 sont
  ; distincts de ceux utilisés par les processus (ils sont
  ; dans une banque de registre différente). Toutefois, les
  ; registres R0 à R7 sont partagés.
  ; Vous pouvez donc utiliser les registres R8 à R15 sans
  ; les sauvegarder préalablement, mais vous DEVEZ sauvegarder la
  ; valeur des registres R0 à R7 inclusivement, l'adresse de retour
  ; et les drapeaux de l'ALU.
  ;
  ; On ne peut pas directement sauvegarder les drapeaux, mais
  ; on peut les transférer dans un registre en utilisant l'instruction
  ; MRS Rx, SPSR (remplacez x par le numéro du registre voulu)
  ; Une fois en possession d'un registre contenant la valeur des drapeaux,
  ; on peut l'envoyer sur la pile pour sauvegarder ces derniers
  ;
  ; De même, on peut transférer un registre général dans le registre
  ; des drapeaux en utilisant l'instruction
  ; MSR SPSR_cxsf, Ry (remplacez y par le numéro du registre voulu)
  ; ATTENTION : les deux instructions (pour écrire et pour lire les drapeaux)
  ; sont DIFFÉRENTES (dans un cas c'est MSR, dans l'autre MRS)
  ;
  ; Lorsqu'une interruption est déclenchée, le processeur termine l'exécution
  ; de l'instruction courante, puis transfère automatiquement
  ; le PC courant dans le registre LR (et non pas l'adresse de retour comme avec BL). 
  ; C'est donc ce registre que vous devez utiliser lorsque vous voulez sauvegarder la position
  ; de l'instruction courante dans chaque processus. N'oubliez toutefois pas
  ; que la valeur de PC correspond à l'adresse de l'instruction qui vient
  ; d'être terminée PLUS 8!
  ;
  ; Étant donnée que les interruptions surviennent à tous les 90 cycles,
  ; votre interruption ne doit jamais demander plus de 80 cycles environ,
  ; sinon les processus n'auront même pas le temps de s'exécuter avant
  ; le déclenchement de la prochaine interruption!
  
  
  ; ÉCRIVEZ VOTRE CODE D'INTERRUPTION ICI

  ; Fin de l'interruption
  SUBS PC, LR, #4               ; On saute à PC-4 (ne pas oublier le +8 du prefetch!)
                                ; pour restaurer l'exécution du processus
                                ; Le S combiné au registre PC comme destination 
                                ; est requis pour indiquer au processeur
                                ; la fin du traitement de l'interruption et
                                ; réactiver les interruptions dans le CPSR


main
initialisation
  MOV R7, #16            ; Ce registre sera utilisé pour indiquer une erreur
                         ; ne pas y toucher, sauf pour le sauvegarder!

  ; On doit activer les interruptions FIQ
  MRS R1, CPSR           ; On copie le registre des drapeaux
  BIC R1, R1, #0x40      ; Ce masque (inversé) contient uniquement des 1, SAUF au bit 6
  MSR CPSR_c, R1         ; On charge la nouvelle valeur dans CPSR
                         ; Cela a pour effet d'activer les interruptions FIQ
                         
  ; ÉCRIVEZ ICI VOTRE CODE D'INITIALISATION
  ;
  ; Ici, vous avez 3 étapes à effectuer :
  ; 1. Initialiser la pile du processus 0
  ; 2. Initialiser la pile du processus 1
  ; 3. Mettre à jour la variable ProcessusCourant pour indiquer au système que 
  ;    c'est le processus 0 qui est exécuté en premier
  ; 
  ; Pour les deux premières étapes, utilisez la fonction initialiseProcessus,
  ; qui fait tout le travail pour vous. Vous n'avez qu'à l'appeler avec les bons paramètres.
  ; (voyez sa documentation pour plus de détails)


  ; Cette instruction devrait être à la fin du bloc d'initialisation
  B processus0           ; On débute l'exécution du premier processus



; NE RIEN MODIFIER À PARTIR D'ICI!

initialiseProcessus
  ; SP : Adresse de la pile du processus
  ; R1 : État des drapeaux souhaité au début de l'exécution du processus
  ; R2 : Adresse de la première instruction du processus
  ; R3 : Nombre de registres généraux à stocker dans la pile
  ; ATTENTION : CETTE FONCTION MODIFIE LES VALEURS DES REGISTRES SP, R3, R2 et R11
  ; SANS LES SAUVEGARDER!
  
  ADD SP, SP, #40       ; On va au sommet de la pile
  ADD R2, R2, #4        ; Pour correspondre à la valeur que le processeur écrit dans LR
                        ; lorsqu'une interruption est déclenchée, on fait pointer LR sur
                        ; la deuxième instruction du processus
  PUSH {R2}             ; On stocke d'abord l'adresse de retour au dessus de la pile
  PUSH {R1}             ; Puis on stocke les drapeaux de l'ALU
  MOV R11, #0
  CMP R3, #0            ; On fait la boucle 'R3' fois
boucleInit
  BXEQ LR
  PUSH {R11}            ; On stocke 0 sur la pile à chaque itération
  SUBS R3, R3, #1
  B boucleInit
  
  
  
  
; Code des processus à exécuter, chaque processus boucle à l'infini
; Vous n'avez pas à comprendre leur fonctionnement
; Toutefois, ils sont conçus pour mettre dans R7 une valeur
; différente de zéro (0) lorsqu'il y a une erreur dans votre
; code. Vous devriez être capable d'exécuter au moins dix
; millions (10 000 000) de cycles en obtenant une valeur finale
; de R7 de 0. Il est normal que cette valeur soit non nulle au départ,
; mais devrait devenir nulle (et le rester) après l'exécution de la
; première instruction de chaque processus.

  MOV R7, #64
processus0
  ; Initialisation
  AND R7, R7, #0x40
  MOV R0, #0
  MOV R1, #0
  MOV R2, #1
  MOV R3, #64
  MOV R4, #0
  MOV R5, #0
  MOV R6, #0
  ; Boucle infinie
boucleP0
  ADD R0, R0, #1
  ADD R1, R1, #2
  ADD R2, R1, #10
  SUBS R3, R3, #1
  MOVEQ R0, #0
  MOVEQ R1, #0
  MOV R0, R0
  MOV R1, R1
  MOVEQ R3, #32
  
  ; Vérification d'erreurs potentielles
  CMP R4, #0
  ORRNE R7, R7, #1
  CMP R5, #0
  ORRNE R7, R7, #1
  CMP R6, #0
  ORRNE R7, R7, #1
  CMP R3, #0
  ORRLT R7, R7, #8
  B boucleP0
  

  MOV R7, #128
processus1
  ; Initialisation
  AND R7, R7, #0x80
  MOV R4, #-1
  MOV R5, #-2
  MOV R6, #0
  ; Boucle infinie
boucleP1
  SUB R4, R4, #1
  SUB R5, R5, #2
  ADD R6, R6, #1
  CMP R6, #53
  MOVEQ R4, #-1
  MOVEQ R5, #-2
  MOV R4, R4
  MOV R5, R5
  MOVEQ R6, #0
  
  ; Vérification d'erreurs potentielles
  CMP R0, #0
  ORRNE R7, R7, #2
  CMP R1, #0
  ORRNE R7, R7, #2
  CMP R2, #0
  ORRNE R7, R7, #2
  CMP R6, #96
  ORRGT R7, R7, #4
  B boucleP1
  


  SECTION `.noinit`:DATA(2)

; Déclaration des piles
; Chaque pile doit pouvoir contenir 10 valeurs de 4 octets, soit :
;       - 8 registres (de R0 à R7 inclusivement)
;       - Les drapeaux (équivalent à un registre)
;       - L'adresse de l'instruction courante (PC)
PileP0        DS32    10                        ; Espace pour la pile du processus 0
PileP1        DS32    10                        ; Espace pour la pile du processus 1

  END
